From 587ebc5d2ee5e56a7949aa305603f54940dd48f9 Mon Sep 17 00:00:00 2001 From: susiwen8 Date: Fri, 5 Feb 2021 18:46:54 +0800 Subject: [PATCH 001/325] Fix: wrong event for `onDidSaveNotebookDocument` --- src/vs/workbench/api/common/extHostNotebook.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts index 49f35f11f9d..daa276d8c86 100644 --- a/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -255,7 +255,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN private _onDidCloseNotebookDocument = new Emitter(); onDidCloseNotebookDocument: Event = this._onDidCloseNotebookDocument.event; private _onDidSaveNotebookDocument = new Emitter(); - onDidSaveNotebookDocument: Event = this._onDidCloseNotebookDocument.event; + onDidSaveNotebookDocument: Event = this._onDidSaveNotebookDocument.event; visibleNotebookEditors: ExtHostNotebookEditor[] = []; private _onDidChangeActiveNotebookKernel = new Emitter<{ document: vscode.NotebookDocument, kernel: vscode.NotebookKernel | undefined; }>(); onDidChangeActiveNotebookKernel = this._onDidChangeActiveNotebookKernel.event; From c88888aa9bcc76b05779edb21c19eb8c7ebac787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Fri, 5 Feb 2021 16:55:20 +0100 Subject: [PATCH 002/325] wip: support overlay context key service related to #114901 --- .../editor/browser/widget/diffEditorWidget.ts | 32 ++--- .../contextkey/browser/contextKeyService.ts | 116 +++++++++++++++--- .../platform/contextkey/common/contextkey.ts | 5 +- .../common/abstractKeybindingService.test.ts | 1 + .../test/common/mockKeybindingService.ts | 3 + .../workbench/browser/parts/views/treeView.ts | 10 +- .../workbench/browser/parts/views/viewPane.ts | 6 +- .../extensions/browser/extensionsActions.ts | 23 ++-- .../notebook/browser/notebookEditorWidget.ts | 2 +- .../browser/view/renderers/cellRenderer.ts | 6 +- .../browser/view/renderers/markdownCell.ts | 5 +- .../contrib/remote/browser/tunnelView.ts | 16 ++- .../contrib/scm/browser/dirtydiffDecorator.ts | 10 +- src/vs/workbench/contrib/scm/browser/menus.ts | 21 ++-- .../contrib/timeline/browser/timelinePane.ts | 10 +- 15 files changed, 165 insertions(+), 101 deletions(-) diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index 014a1d68506..022b35455db 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -222,7 +222,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE private readonly _updateDecorationsRunner: RunOnceScheduler; private readonly _editorWorkerService: IEditorWorkerService; - protected _contextKeyService: IContextKeyService; + private readonly _contextKeyService: IContextKeyService; + private readonly _instantiationService: IInstantiationService; private readonly _codeEditorService: ICodeEditorService; private readonly _themeService: IThemeService; private readonly _notificationService: INotificationService; @@ -248,6 +249,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE this._editorWorkerService = editorWorkerService; this._codeEditorService = codeEditorService; this._contextKeyService = this._register(contextKeyService.createScoped(domElement)); + this._instantiationService = instantiationService.createChild(new ServiceCollection([IContextKeyService, this._contextKeyService])); this._contextKeyService.createKey('isInDiffEditor', true); this._themeService = themeService; this._notificationService = notificationService; @@ -354,20 +356,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE this._diffComputationResult = null; - const leftContextKeyService = this._contextKeyService.createScoped(); - - const leftServices = new ServiceCollection(); - leftServices.set(IContextKeyService, leftContextKeyService); - const leftScopedInstantiationService = instantiationService.createChild(leftServices); - - const rightContextKeyService = this._contextKeyService.createScoped(); - - const rightServices = new ServiceCollection(); - rightServices.set(IContextKeyService, rightContextKeyService); - const rightScopedInstantiationService = instantiationService.createChild(rightServices); - - this._originalEditor = this._createLeftHandSideEditor(options, codeEditorWidgetOptions.originalEditor || {}, leftScopedInstantiationService, leftContextKeyService); - this._modifiedEditor = this._createRightHandSideEditor(options, codeEditorWidgetOptions.modifiedEditor || {}, rightScopedInstantiationService, rightContextKeyService); + this._originalEditor = this._createLeftHandSideEditor(options, codeEditorWidgetOptions.originalEditor || {}); + this._modifiedEditor = this._createRightHandSideEditor(options, codeEditorWidgetOptions.modifiedEditor || {}); this._originalOverviewRuler = null; this._modifiedOverviewRuler = null; @@ -495,8 +485,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE this._layoutOverviewRulers(); } - private _createLeftHandSideEditor(options: Readonly, codeEditorWidgetOptions: ICodeEditorWidgetOptions, instantiationService: IInstantiationService, contextKeyService: IContextKeyService): CodeEditorWidget { - const editor = this._createInnerEditor(instantiationService, this._originalDomNode, this._adjustOptionsForLeftHandSide(options), codeEditorWidgetOptions); + private _createLeftHandSideEditor(options: Readonly, codeEditorWidgetOptions: ICodeEditorWidgetOptions): CodeEditorWidget { + const editor = this._createInnerEditor(this._instantiationService, this._originalDomNode, this._adjustOptionsForLeftHandSide(options), codeEditorWidgetOptions); this._register(editor.onDidScrollChange((e) => { if (this._isHandlingScrollEvent) { @@ -538,7 +528,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE } })); - const isInDiffLeftEditorKey = contextKeyService.createKey('isInDiffLeftEditor', undefined); + const isInDiffLeftEditorKey = this._contextKeyService.createKey('isInDiffLeftEditor', editor.hasWidgetFocus()); this._register(editor.onDidFocusEditorWidget(() => isInDiffLeftEditorKey.set(true))); this._register(editor.onDidBlurEditorWidget(() => isInDiffLeftEditorKey.set(false))); @@ -557,8 +547,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE return editor; } - private _createRightHandSideEditor(options: Readonly, codeEditorWidgetOptions: ICodeEditorWidgetOptions, instantiationService: IInstantiationService, contextKeyService: IContextKeyService): CodeEditorWidget { - const editor = this._createInnerEditor(instantiationService, this._modifiedDomNode, this._adjustOptionsForRightHandSide(options), codeEditorWidgetOptions); + private _createRightHandSideEditor(options: Readonly, codeEditorWidgetOptions: ICodeEditorWidgetOptions): CodeEditorWidget { + const editor = this._createInnerEditor(this._instantiationService, this._modifiedDomNode, this._adjustOptionsForRightHandSide(options), codeEditorWidgetOptions); this._register(editor.onDidScrollChange((e) => { if (this._isHandlingScrollEvent) { @@ -606,7 +596,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE } })); - const isInDiffRightEditorKey = contextKeyService.createKey('isInDiffRightEditor', undefined); + const isInDiffRightEditorKey = this._contextKeyService.createKey('isInDiffRightEditor', editor.hasWidgetFocus()); this._register(editor.onDidFocusEditorWidget(() => isInDiffRightEditorKey.set(true))); this._register(editor.onDidBlurEditorWidget(() => isInDiffRightEditorKey.set(false))); diff --git a/src/vs/platform/contextkey/browser/contextKeyService.ts b/src/vs/platform/contextkey/browser/contextKeyService.ts index df2e5b70dbe..b1d43b2c7d9 100644 --- a/src/vs/platform/contextkey/browser/contextKeyService.ts +++ b/src/vs/platform/contextkey/browser/contextKeyService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Emitter, PauseableEmitter } from 'vs/base/common/event'; +import { Emitter, Event, PauseableEmitter } from 'vs/base/common/event'; import { Iterable } from 'vs/base/common/iterator'; import { IDisposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; import { TernarySearchTree } from 'vs/base/common/map'; @@ -287,6 +287,13 @@ export abstract class AbstractContextKeyService implements IContextKeyService { return new ScopedContextKeyService(this, domNode); } + createOverlay(overlay: Iterable<[string, any]> = Iterable.empty()): IContextKeyService { + if (this._isDisposed) { + throw new Error(`AbstractContextKeyService has been disposed`); + } + return new OverlayContextKeyService(this, overlay); + } + public contextMatchesRules(rules: ContextKeyExpression | undefined): boolean { if (this._isDisposed) { throw new Error(`AbstractContextKeyService has been disposed`); @@ -405,27 +412,25 @@ export class ContextKeyService extends AbstractContextKeyService implements ICon class ScopedContextKeyService extends AbstractContextKeyService { private _parent: AbstractContextKeyService; - private _domNode: IContextKeyServiceTarget | undefined; + private _domNode: IContextKeyServiceTarget; private readonly _parentChangeListener = new MutableDisposable(); - constructor(parent: AbstractContextKeyService, domNode?: IContextKeyServiceTarget) { + constructor(parent: AbstractContextKeyService, domNode: IContextKeyServiceTarget) { super(parent.createChildContext()); this._parent = parent; this._updateParentChangeListener(); - if (domNode) { - this._domNode = domNode; - if (this._domNode.hasAttribute(KEYBINDING_CONTEXT_ATTR)) { - let extraInfo = ''; - if ((this._domNode as HTMLElement).classList) { - extraInfo = Array.from((this._domNode as HTMLElement).classList.values()).join(', '); - } - - console.error(`Element already has context attribute${extraInfo ? ': ' + extraInfo : ''}`); + this._domNode = domNode; + if (this._domNode.hasAttribute(KEYBINDING_CONTEXT_ATTR)) { + let extraInfo = ''; + if ((this._domNode as HTMLElement).classList) { + extraInfo = Array.from((this._domNode as HTMLElement).classList.values()).join(', '); } - this._domNode.setAttribute(KEYBINDING_CONTEXT_ATTR, String(this._myContextId)); + + console.error(`Element already has context attribute${extraInfo ? ': ' + extraInfo : ''}`); } + this._domNode.setAttribute(KEYBINDING_CONTEXT_ATTR, String(this._myContextId)); } private _updateParentChangeListener(): void { @@ -434,14 +439,15 @@ class ScopedContextKeyService extends AbstractContextKeyService { } public dispose(): void { - this._onDidChangeContext.dispose(); - this._isDisposed = true; - this._parent.disposeContext(this._myContextId); - this._parentChangeListener?.dispose(); - if (this._domNode) { - this._domNode.removeAttribute(KEYBINDING_CONTEXT_ATTR); - this._domNode = undefined; + if (this._isDisposed) { + return; } + + this._onDidChangeContext.dispose(); + this._parent.disposeContext(this._myContextId); + this._parentChangeListener.dispose(); + this._domNode.removeAttribute(KEYBINDING_CONTEXT_ATTR); + this._isDisposed = true; } public getContextValuesContainer(contextId: number): Context { @@ -484,6 +490,76 @@ class ScopedContextKeyService extends AbstractContextKeyService { } } +class OverlayContext implements IContext { + + constructor(private parent: IContext, private overlay: ReadonlyMap) { } + + getValue(key: string): T | undefined { + return this.overlay.has(key) ? this.overlay.get(key) : this.parent.getValue(key); + } +} + +class OverlayContextKeyService implements IContextKeyService { + + declare _serviceBrand: undefined; + private overlay: Map; + + get contextId(): number { + return this.parent.contextId; + } + + get onDidChangeContext(): Event { + return this.parent.onDidChangeContext; + } + + constructor(private parent: AbstractContextKeyService | OverlayContextKeyService, overlay: Iterable<[string, any]>) { + this.overlay = new Map(overlay); + } + + bufferChangeEvents(callback: Function): void { + this.parent.bufferChangeEvents(callback); + } + + createKey(): IContextKey { + throw new Error('Not supported.'); + } + + getContext(target: IContextKeyServiceTarget | null): IContext { + return new OverlayContext(this.parent.getContext(target), this.overlay); + } + + getContextValuesContainer(contextId: number): IContext { + const parentContext = this.parent.getContextValuesContainer(contextId); + return new OverlayContext(parentContext, this.overlay); + } + + contextMatchesRules(rules: ContextKeyExpression | undefined): boolean { + const context = this.getContextValuesContainer(this.contextId); + const result = KeybindingResolver.contextMatchesRules(context, rules); + return result; + } + + getContextKeyValue(key: string): T | undefined { + return this.overlay.has(key) ? this.overlay.get(key) : this.parent.getContextKeyValue(key); + } + + createScoped(): IContextKeyService { + throw new Error('Not supported.'); + } + + createOverlay(overlay: Iterable<[string, any]> = Iterable.empty()): IContextKeyService { + return new OverlayContextKeyService(this, overlay); + } + + updateParent(): void { + throw new Error('Not supported.'); + } + + dispose(): void { + // noop + } +} + function findContextAttr(domNode: IContextKeyServiceTarget | null): number { while (domNode) { if (domNode.hasAttribute(KEYBINDING_CONTEXT_ATTR)) { diff --git a/src/vs/platform/contextkey/common/contextkey.ts b/src/vs/platform/contextkey/common/contextkey.ts index fde5606ea23..76cbd9c2696 100644 --- a/src/vs/platform/contextkey/common/contextkey.ts +++ b/src/vs/platform/contextkey/common/contextkey.ts @@ -1261,7 +1261,7 @@ export class RawContextKey extends ContextKeyDefinedExpr { private readonly _defaultValue: T | undefined; - constructor(key: string, defaultValue: T | undefined) { + constructor(readonly key: string, defaultValue: T | undefined) { super(key); this._defaultValue = defaultValue; } @@ -1326,7 +1326,8 @@ export interface IContextKeyService { contextMatchesRules(rules: ContextKeyExpression | undefined): boolean; getContextKeyValue(key: string): T | undefined; - createScoped(target?: IContextKeyServiceTarget): IContextKeyService; + createScoped(target: IContextKeyServiceTarget): IContextKeyService; + createOverlay(overlay: Iterable<[string, any]>): IContextKeyService; getContext(target: IContextKeyServiceTarget | null): IContext; updateParent(parentContextKeyService: IContextKeyService): void; diff --git a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts index d627e662606..ec890db1260 100644 --- a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts +++ b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts @@ -118,6 +118,7 @@ suite('AbstractKeybindingService', () => { contextMatchesRules: undefined!, getContextKeyValue: undefined!, createScoped: undefined!, + createOverlay: undefined!, getContext: (target: IContextKeyServiceTarget): any => { return currentContextValue; }, diff --git a/src/vs/platform/keybinding/test/common/mockKeybindingService.ts b/src/vs/platform/keybinding/test/common/mockKeybindingService.ts index bc03b1feabc..2fe7bbabca9 100644 --- a/src/vs/platform/keybinding/test/common/mockKeybindingService.ts +++ b/src/vs/platform/keybinding/test/common/mockKeybindingService.ts @@ -66,6 +66,9 @@ export class MockContextKeyService implements IContextKeyService { public createScoped(domNode: HTMLElement): IContextKeyService { return this; } + public createOverlay(): IContextKeyService { + return this; + } updateParent(_parentContextKeyService: IContextKeyService): void { // no-op } diff --git a/src/vs/workbench/browser/parts/views/treeView.ts b/src/vs/workbench/browser/parts/views/treeView.ts index e5e388f6102..9c49ffdcca2 100644 --- a/src/vs/workbench/browser/parts/views/treeView.ts +++ b/src/vs/workbench/browser/parts/views/treeView.ts @@ -1123,18 +1123,18 @@ class TreeMenus extends Disposable implements IDisposable { if (!this.contextKeyService) { return { primary: [], secondary: [] }; } - const contextKeyService = this.contextKeyService.createScoped(); - contextKeyService.createKey('view', this.id); - contextKeyService.createKey(context.key, context.value); + + const contextKeyService = this.contextKeyService.createOverlay([ + ['view', this.id], + [context.key, context.value] + ]); const menu = this.menuService.createMenu(menuId, contextKeyService); const primary: IAction[] = []; const secondary: IAction[] = []; const result = { primary, secondary }; createAndFillInContextMenuActions(menu, { shouldForwardArgs: true }, result, g => /^inline/.test(g)); - menu.dispose(); - contextKeyService.dispose(); return result; } diff --git a/src/vs/workbench/browser/parts/views/viewPane.ts b/src/vs/workbench/browser/parts/views/viewPane.ts index 27f5af3cfb0..a697bebf33c 100644 --- a/src/vs/workbench/browser/parts/views/viewPane.ts +++ b/src/vs/workbench/browser/parts/views/viewPane.ts @@ -80,16 +80,12 @@ class ViewWelcomeController { return visibleItems.map(v => v.descriptor); } - private contextKeyService: IContextKeyService; private disposables = new DisposableStore(); constructor( private id: string, - @IContextKeyService contextKeyService: IContextKeyService, + @IContextKeyService private contextKeyService: IContextKeyService, ) { - this.contextKeyService = contextKeyService.createScoped(); - this.disposables.add(this.contextKeyService); - contextKeyService.onDidChangeContext(this.onDidChangeContext, this, this.disposables); Event.filter(viewsRegistry.onDidChangeViewWelcomeContent, id => id === this.id)(this.onDidChangeViewWelcomeContent, this, this.disposables); this.onDidChangeViewWelcomeContent(); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index 3401152e5ca..314bbcd896d 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -858,25 +858,27 @@ export class DropDownMenuActionViewItem extends ExtensionActionViewItem { export function getContextMenuActions(extension: IExtension | undefined | null, inExtensionEditor: boolean, instantiationService: IInstantiationService): IAction[][] { return instantiationService.invokeFunction(accessor => { - const scopedContextKeyService = accessor.get(IContextKeyService).createScoped(); const menuService = accessor.get(IMenuService); const extensionRecommendationsService = accessor.get(IExtensionRecommendationsService); const extensionIgnoredRecommendationsService = accessor.get(IExtensionIgnoredRecommendationsService); + const cksOverlay: [string, any][] = []; + if (extension) { - scopedContextKeyService.createKey('extension', extension.identifier.id); - scopedContextKeyService.createKey('isBuiltinExtension', extension.isBuiltin); - scopedContextKeyService.createKey('extensionHasConfiguration', extension.local && !!extension.local.manifest.contributes && !!extension.local.manifest.contributes.configuration); - scopedContextKeyService.createKey('isExtensionRecommended', !!extensionRecommendationsService.getAllRecommendationsWithReason()[extension.identifier.id.toLowerCase()]); - scopedContextKeyService.createKey('isExtensionWorkspaceRecommended', extensionRecommendationsService.getAllRecommendationsWithReason()[extension.identifier.id.toLowerCase()]?.reasonId === ExtensionRecommendationReason.Workspace); - scopedContextKeyService.createKey('isUserIgnoredRecommendation', extensionIgnoredRecommendationsService.globalIgnoredRecommendations.some(e => e === extension.identifier.id.toLowerCase())); - scopedContextKeyService.createKey('inExtensionEditor', inExtensionEditor); + cksOverlay.push(['extension', extension.identifier.id]); + cksOverlay.push(['isBuiltinExtension', extension.isBuiltin]); + cksOverlay.push(['extensionHasConfiguration', extension.local && !!extension.local.manifest.contributes && !!extension.local.manifest.contributes.configuration]); + cksOverlay.push(['isExtensionRecommended', !!extensionRecommendationsService.getAllRecommendationsWithReason()[extension.identifier.id.toLowerCase()]]); + cksOverlay.push(['isExtensionWorkspaceRecommended', extensionRecommendationsService.getAllRecommendationsWithReason()[extension.identifier.id.toLowerCase()]?.reasonId === ExtensionRecommendationReason.Workspace]); + cksOverlay.push(['isUserIgnoredRecommendation', extensionIgnoredRecommendationsService.globalIgnoredRecommendations.some(e => e === extension.identifier.id.toLowerCase())]); + cksOverlay.push(['inExtensionEditor', inExtensionEditor]); if (extension.state === ExtensionState.Installed) { - scopedContextKeyService.createKey('extensionStatus', 'installed'); + cksOverlay.push(['extensionStatus', 'installed']); } } + const contextKeyService = accessor.get(IContextKeyService).createOverlay(cksOverlay); const groups: IAction[][] = []; - const menu = menuService.createMenu(MenuId.ExtensionContext, scopedContextKeyService); + const menu = menuService.createMenu(MenuId.ExtensionContext, contextKeyService); menu.getActions({ shouldForwardArgs: true }).forEach(([, actions]) => groups.push(actions.map(action => { if (action instanceof SubmenuAction) { return action; @@ -884,7 +886,6 @@ export function getContextMenuActions(extension: IExtension | undefined | null, return instantiationService.createInstance(MenuItemExtensionAction, action); }))); menu.dispose(); - scopedContextKeyService.dispose(); return groups; }); diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 21568d5743b..0f219813238 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -462,7 +462,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor this._body.classList.add('cell-list-container'); this._dndController = this._register(new CellDragAndDropController(this, this._body)); - const getScopedContextKeyService = (container?: HTMLElement) => this._list.contextKeyService.createScoped(container); + const getScopedContextKeyService = (container: HTMLElement) => this._list.contextKeyService.createScoped(container); const renderers = [ this.instantiationService.createInstance(CodeCellRenderer, this, this._renderedEditors, this._dndController, getScopedContextKeyService), this.instantiationService.createInstance(MarkdownCellRenderer, this, this._dndController, this._renderedEditors, getScopedContextKeyService), diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts index ad254bc8fe2..752235dfb9f 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -178,7 +178,7 @@ abstract class AbstractCellRenderer { configurationService: IConfigurationService, private readonly keybindingService: IKeybindingService, private readonly notificationService: INotificationService, - protected readonly contextKeyServiceProvider: (container?: HTMLElement) => IContextKeyService, + protected readonly contextKeyServiceProvider: (container: HTMLElement) => IContextKeyService, language: string, protected readonly dndController: CellDragAndDropController ) { @@ -375,7 +375,7 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR notebookEditor: INotebookEditor, dndController: CellDragAndDropController, private renderedEditors: Map, - contextKeyServiceProvider: (container?: HTMLElement) => IContextKeyService, + contextKeyServiceProvider: (container: HTMLElement) => IContextKeyService, @IInstantiationService instantiationService: IInstantiationService, @IConfigurationService configurationService: IConfigurationService, @IContextMenuService contextMenuService: IContextMenuService, @@ -669,7 +669,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende protected notebookEditor: INotebookEditor, private renderedEditors: Map, dndController: CellDragAndDropController, - contextKeyServiceProvider: (container?: HTMLElement) => IContextKeyService, + contextKeyServiceProvider: (container: HTMLElement) => IContextKeyService, @IContextMenuService contextMenuService: IContextMenuService, @IConfigurationService configurationService: IConfigurationService, @IInstantiationService instantiationService: IInstantiationService, diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts index ae7a1fe9b85..081eb777bff 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts @@ -223,9 +223,10 @@ export class StatefulMarkdownCell extends Disposable { this.templateData.editorContainer.innerText = ''; // create a special context key service that set the inCompositeEditor-contextkey - const editorContextKeyService = this.contextKeyService.createScoped(); + const editorContextKeyService = this.contextKeyService.createOverlay([ + [EditorContextKeys.inCompositeEditor.key, true] + ]); const editorInstaService = this.instantiationService.createChild(new ServiceCollection([IContextKeyService, editorContextKeyService])); - EditorContextKeys.inCompositeEditor.bindTo(editorContextKeyService).set(true); this.editor = editorInstaService.createInstance(CodeEditorWidget, this.templateData.editorContainer, { ...this.editorOptions, diff --git a/src/vs/workbench/contrib/remote/browser/tunnelView.ts b/src/vs/workbench/contrib/remote/browser/tunnelView.ts index f0fdc0ff816..959fa569cf4 100644 --- a/src/vs/workbench/contrib/remote/browser/tunnelView.ts +++ b/src/vs/workbench/contrib/remote/browser/tunnelView.ts @@ -268,10 +268,11 @@ class TunnelTreeRenderer extends Disposable implements ITreeRenderer { this.titleActions = []; this.titleActionsDisposable.value = createAndFillInActionBarActions(titleMenu, undefined, this.titleActions); diff --git a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts index ffd41e575a8..a728a5af0bc 100644 --- a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts @@ -169,7 +169,6 @@ class DirtyDiffWidget extends PeekViewWidget { private index: number = 0; private change: IChange | undefined; private height: number | undefined = undefined; - private contextKeyService: IContextKeyService; constructor( editor: ICodeEditor, @@ -177,16 +176,17 @@ class DirtyDiffWidget extends PeekViewWidget { @IThemeService private readonly themeService: IThemeService, @IInstantiationService instantiationService: IInstantiationService, @IMenuService menuService: IMenuService, - @IContextKeyService contextKeyService: IContextKeyService + @IContextKeyService _contextKeyService: IContextKeyService ) { super(editor, { isResizeable: true, frameWidth: 1, keepEditorSelection: true }, instantiationService); this._disposables.add(themeService.onDidColorThemeChange(this._applyTheme, this)); this._applyTheme(themeService.getColorTheme()); - this.contextKeyService = contextKeyService.createScoped(); - this.contextKeyService.createKey('originalResourceScheme', this.model.original!.uri.scheme); - this.menu = menuService.createMenu(MenuId.SCMChangeContext, this.contextKeyService); + const contextKeyService = _contextKeyService.createOverlay([ + ['originalResourceScheme', this.model.original!.uri.scheme] + ]); + this.menu = menuService.createMenu(MenuId.SCMChangeContext, contextKeyService); this.create(); if (editor.hasModel()) { diff --git a/src/vs/workbench/contrib/scm/browser/menus.ts b/src/vs/workbench/contrib/scm/browser/menus.ts index 4fd31d3a776..8580f1134fc 100644 --- a/src/vs/workbench/contrib/scm/browser/menus.ts +++ b/src/vs/workbench/contrib/scm/browser/menus.ts @@ -119,15 +119,12 @@ class SCMMenusItem implements IDisposable { let item = this.contextualResourceMenus.get(resource.contextValue); if (!item) { - const contextKeyService = this.contextKeyService.createScoped(); - contextKeyService.createKey('scmResourceState', resource.contextValue); - + const contextKeyService = this.contextKeyService.createOverlay([['scmResourceState', resource.contextValue]]); const menu = this.menuService.createMenu(MenuId.SCMResourceContext, contextKeyService); item = { menu, dispose() { menu.dispose(); - contextKeyService.dispose(); } }; @@ -148,7 +145,6 @@ class SCMMenusItem implements IDisposable { } this.resourceFolderMenu?.dispose(); - this.contextKeyService.dispose(); } } @@ -178,10 +174,11 @@ export class SCMRepositoryMenus implements ISCMRepositoryMenus, IDisposable { @IInstantiationService instantiationService: IInstantiationService, @IMenuService private readonly menuService: IMenuService ) { - this.contextKeyService = contextKeyService.createScoped(); - this.contextKeyService.createKey('scmProvider', provider.contextValue); - this.contextKeyService.createKey('scmProviderRootUri', provider.rootUri?.toString()); - this.contextKeyService.createKey('scmProviderHasRootUri', !!provider.rootUri); + this.contextKeyService = contextKeyService.createOverlay([ + ['scmProvider', provider.contextValue], + ['scmProviderRootUri', provider.rootUri?.toString()], + ['scmProviderHasRootUri', !!provider.rootUri], + ]); const serviceCollection = new ServiceCollection([IContextKeyService, this.contextKeyService]); instantiationService = instantiationService.createChild(serviceCollection); @@ -207,9 +204,9 @@ export class SCMRepositoryMenus implements ISCMRepositoryMenus, IDisposable { let result = this.resourceGroupMenusItems.get(group); if (!result) { - const contextKeyService = this.contextKeyService.createScoped(); - contextKeyService.createKey('scmProvider', group.provider.contextValue); - contextKeyService.createKey('scmResourceGroup', group.id); + const contextKeyService = this.contextKeyService.createOverlay([ + ['scmResourceGroup', group.id], + ]); result = new SCMMenusItem(contextKeyService, this.menuService); this.resourceGroupMenusItems.set(group, result); diff --git a/src/vs/workbench/contrib/timeline/browser/timelinePane.ts b/src/vs/workbench/contrib/timeline/browser/timelinePane.ts index 2057bc5a2aa..0cfcc567e6f 100644 --- a/src/vs/workbench/contrib/timeline/browser/timelinePane.ts +++ b/src/vs/workbench/contrib/timeline/browser/timelinePane.ts @@ -1223,18 +1223,18 @@ class TimelinePaneCommands extends Disposable { } private getActions(menuId: MenuId, context: { key: string, value?: string }): { primary: IAction[]; secondary: IAction[]; } { - const scoped = this.contextKeyService.createScoped(); - scoped.createKey('view', this.pane.id); - scoped.createKey(context.key, context.value); + const contextKeyService = this.contextKeyService.createOverlay([ + ['view', this.pane.id], + [context.key, context.value], + ]); - const menu = this.menuService.createMenu(menuId, scoped); + const menu = this.menuService.createMenu(menuId, contextKeyService); const primary: IAction[] = []; const secondary: IAction[] = []; const result = { primary, secondary }; createAndFillInContextMenuActions(menu, { shouldForwardArgs: true }, result, g => /^inline/.test(g)); menu.dispose(); - scoped.dispose(); return result; } From d2a6b516e4f95dc4413f65f31ff9f133ef90c42d Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 10 Feb 2021 15:27:34 +0100 Subject: [PATCH 003/325] add check box to use insiders settings sync service while switching --- src/vs/code/browser/workbench/workbench.ts | 2 +- .../userDataSync/common/userDataSync.ts | 1 + .../common/userDataSyncStoreService.ts | 16 +++-- .../contrib/update/browser/update.ts | 71 +++++++++++++------ .../userDataSync/browser/userDataSync.ts | 8 --- .../sandbox.simpleservices.ts | 2 + 6 files changed, 63 insertions(+), 37 deletions(-) diff --git a/src/vs/code/browser/workbench/workbench.ts b/src/vs/code/browser/workbench/workbench.ts index 415d82a72f5..337e04c1fc3 100644 --- a/src/vs/code/browser/workbench/workbench.ts +++ b/src/vs/code/browser/workbench/workbench.ts @@ -275,7 +275,7 @@ class WorkspaceProvider implements IWorkspaceProvider { static QUERY_PARAM_PAYLOAD = 'payload'; - readonly trusted = undefined; + readonly trusted = true; constructor( public readonly workspace: IWorkspace, diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index 310fea185f2..ef13265a4fb 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -149,6 +149,7 @@ export interface IUserDataSyncStoreManagementService { readonly _serviceBrand: undefined; readonly onDidChangeUserDataSyncStore: Event; readonly userDataSyncStore: IUserDataSyncStore | undefined; + set(type: UserDataSyncStoreType): void; switch(type: UserDataSyncStoreType): Promise; getPreviousUserDataSyncStore(): Promise; } diff --git a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts index a4bde40f314..4ff7398cfa9 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts @@ -89,6 +89,16 @@ export abstract class AbstractUserDataSyncStoreManagementService extends Disposa return undefined; } + set(type: UserDataSyncStoreType) { + if (this.userDataSyncStore) { + if (type === this.userDataSyncStore.defaultType) { + this.storageService.remove(SYNC_SERVICE_URL_TYPE, StorageScope.GLOBAL); + } else { + this.storageService.store(SYNC_SERVICE_URL_TYPE, type, StorageScope.GLOBAL, StorageTarget.MACHINE); + } + } + } + abstract switch(type: UserDataSyncStoreType): Promise; abstract getPreviousUserDataSyncStore(): Promise; @@ -120,11 +130,7 @@ export class UserDataSyncStoreManagementService extends AbstractUserDataSyncStor async switch(type: UserDataSyncStoreType): Promise { if (this.userDataSyncStore?.canSwitch && type !== this.userDataSyncStore.type) { - if (type === this.userDataSyncStore.defaultType) { - this.storageService.remove(SYNC_SERVICE_URL_TYPE, StorageScope.GLOBAL); - } else { - this.storageService.store(SYNC_SERVICE_URL_TYPE, type, StorageScope.GLOBAL, StorageTarget.MACHINE); - } + this.set(type); this.updateUserDataSyncStore(); } } diff --git a/src/vs/workbench/contrib/update/browser/update.ts b/src/vs/workbench/contrib/update/browser/update.ts index 06699f71d48..c14d01a86a0 100644 --- a/src/vs/workbench/contrib/update/browser/update.ts +++ b/src/vs/workbench/contrib/update/browser/update.ts @@ -9,7 +9,7 @@ import { Action } from 'vs/base/common/actions'; import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IActivityService, NumberBadge, IBadge, ProgressBadge } from 'vs/workbench/services/activity/common/activity'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; @@ -21,12 +21,14 @@ import { ReleaseNotesManager } from './releaseNotesEditor'; import { isWindows } from 'vs/base/common/platform'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { RawContextKey, IContextKey, IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; +import { MenuRegistry, MenuId, registerAction2, Action2 } from 'vs/platform/actions/common/actions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ShowCurrentReleaseNotesActionId, CheckForVSCodeUpdateActionId } from 'vs/workbench/contrib/update/common/update'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IProductService } from 'vs/platform/product/common/productService'; import product from 'vs/platform/product/common/product'; +import { IUserDataAutoSyncEnablementService, IUserDataSyncStoreManagementService } from 'vs/platform/userDataSync/common/userDataSync'; +import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; export const CONTEXT_UPDATE_STATE = new RawContextKey('updateState', StateType.Idle); @@ -511,7 +513,7 @@ export class SwitchProductQualityContribution extends Disposable implements IWor constructor( @IProductService private readonly productService: IProductService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService + @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, ) { super(); @@ -524,27 +526,50 @@ export class SwitchProductQualityContribution extends Disposable implements IWor if (productQualityChangeHandler && (quality === 'stable' || quality === 'insider')) { const newQuality = quality === 'stable' ? 'insider' : 'stable'; const commandId = `update.switchQuality.${newQuality}`; - CommandsRegistry.registerCommand(commandId, async accessor => { - const dialogService = accessor.get(IDialogService); - - const res = await dialogService.confirm({ - type: 'info', - message: nls.localize('relaunchMessage', "Changing the version requires a reload to take effect"), - detail: newQuality === 'insider' ? - nls.localize('relaunchDetailInsiders', "Press the reload button to switch to the nightly pre-production version of VSCode.") : - nls.localize('relaunchDetailStable', "Press the reload button to switch to the monthly released stable version of VSCode."), - primaryButton: nls.localize('reload', "&&Reload") - }); - - if (res.confirmed) { - productQualityChangeHandler(newQuality); + const isSwitchingToInsiders = newQuality === 'insider'; + registerAction2(class SwitchQuality extends Action2 { + constructor() { + super({ + id: commandId, + title: isSwitchingToInsiders ? nls.localize('switchToInsiders', "Switch to Insiders Version...") : nls.localize('switchToStable', "Switch to Stable Version..."), + precondition: IsWebContext, + menu: { + id: MenuId.GlobalActivity, + when: IsWebContext, + group: '6_update', + } + }); } - }); - MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { - group: '6_update', - command: { - id: commandId, - title: newQuality === 'insider' ? nls.localize('switchToInsiders', "Switch to Insiders Version...") : nls.localize('switchToStable', "Switch to Stable Version...") + async run(accessor: ServicesAccessor): Promise { + const dialogService = accessor.get(IDialogService); + const userDataAutoSyncEnablementService = accessor.get(IUserDataAutoSyncEnablementService); + const userDataSyncStoreManagementService = accessor.get(IUserDataSyncStoreManagementService); + const storageService = accessor.get(IStorageService); + + const askToUseInsidersSettingsSyncService = isSwitchingToInsiders && userDataAutoSyncEnablementService.isEnabled(); + const useInsidersSettingsSyncServiceCheckedKey = 'switchQuality.useInsidersSettingsSyncService.checked'; + + const res = await dialogService.confirm({ + type: 'info', + message: askToUseInsidersSettingsSyncService ? nls.localize('relaunchMessage1', "Choose Settings Sync service and Reload") + : nls.localize('relaunchMessage2', "Changing the version requires a reload to take effect"), + detail: isSwitchingToInsiders ? + nls.localize('relaunchDetailInsiders', "Press the reload button to switch to the nightly pre-production version of VSCode.") : + nls.localize('relaunchDetailStable', "Press the reload button to switch to the monthly released stable version of VSCode."), + checkbox: askToUseInsidersSettingsSyncService ? { + label: nls.localize('useInsidersSyncService.description', "Use Insiders Settings Sync service for syncing."), + checked: storageService.getBoolean(useInsidersSettingsSyncServiceCheckedKey, StorageScope.GLOBAL, true) + } : undefined, + primaryButton: nls.localize('reload', "&&Reload") + }); + + if (res.confirmed) { + if (askToUseInsidersSettingsSyncService) { + storageService.store(useInsidersSettingsSyncServiceCheckedKey, !!res.checkboxChecked, StorageScope.GLOBAL, StorageTarget.USER); + userDataSyncStoreManagementService.switch(res.checkboxChecked ? 'insiders' : 'stable'); + } + productQualityChangeHandler(newQuality); + } } }); } diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 33b6202653d..bd9aadf11d9 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -323,14 +323,6 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } }); return; - case UserDataSyncErrorCode.DefaultServiceChanged: - if (isEqual(this.userDataSyncStoreManagementService.userDataSyncStore?.url, this.userDataSyncStoreManagementService.userDataSyncStore?.insidersUrl)) { - this.notificationService.notify({ - severity: Severity.Info, - message: localize('switched to insiders', "Settings sync now uses a separate service, more information is available in the [release notes](https://code.visualstudio.com/updates/v1_48#_settings-sync)."), - }); - } - return; } } diff --git a/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts b/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts index 4a2f05f35f9..e8234813c97 100644 --- a/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts +++ b/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts @@ -644,6 +644,8 @@ class SimpleUserDataSyncStoreManagementService implements IUserDataSyncStoreMana userDataSyncStore: IUserDataSyncStore | undefined = undefined; + set(type: UserDataSyncStoreType): void { } + async switch(type: UserDataSyncStoreType): Promise { } async getPreviousUserDataSyncStore(): Promise { return undefined; } From 49e2e2b1392d6bc4a50d56051a3af2326549ef3b Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 10 Feb 2021 20:11:45 +0100 Subject: [PATCH 004/325] show selecting settings sync service as a separate dialog --- .../common/userDataSyncStoreService.ts | 12 ++--- .../contrib/update/browser/update.ts | 47 ++++++++++++++----- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts index 4ff7398cfa9..a2680a644cb 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts @@ -91,11 +91,7 @@ export abstract class AbstractUserDataSyncStoreManagementService extends Disposa set(type: UserDataSyncStoreType) { if (this.userDataSyncStore) { - if (type === this.userDataSyncStore.defaultType) { - this.storageService.remove(SYNC_SERVICE_URL_TYPE, StorageScope.GLOBAL); - } else { - this.storageService.store(SYNC_SERVICE_URL_TYPE, type, StorageScope.GLOBAL, StorageTarget.MACHINE); - } + this.storageService.store(SYNC_SERVICE_URL_TYPE, type, StorageScope.GLOBAL, StorageTarget.MACHINE); } } @@ -130,7 +126,11 @@ export class UserDataSyncStoreManagementService extends AbstractUserDataSyncStor async switch(type: UserDataSyncStoreType): Promise { if (this.userDataSyncStore?.canSwitch && type !== this.userDataSyncStore.type) { - this.set(type); + if (type === this.userDataSyncStore.defaultType) { + this.storageService.remove(SYNC_SERVICE_URL_TYPE, StorageScope.GLOBAL); + } else { + this.set(type); + } this.updateUserDataSyncStore(); } } diff --git a/src/vs/workbench/contrib/update/browser/update.ts b/src/vs/workbench/contrib/update/browser/update.ts index c14d01a86a0..ec779434d7e 100644 --- a/src/vs/workbench/contrib/update/browser/update.ts +++ b/src/vs/workbench/contrib/update/browser/update.ts @@ -27,7 +27,7 @@ import { ShowCurrentReleaseNotesActionId, CheckForVSCodeUpdateActionId } from 'v import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IProductService } from 'vs/platform/product/common/productService'; import product from 'vs/platform/product/common/product'; -import { IUserDataAutoSyncEnablementService, IUserDataSyncStoreManagementService } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataAutoSyncEnablementService, IUserDataSyncStoreManagementService, UserDataSyncStoreType } from 'vs/platform/userDataSync/common/userDataSync'; import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; export const CONTEXT_UPDATE_STATE = new RawContextKey('updateState', StateType.Idle); @@ -540,37 +540,58 @@ export class SwitchProductQualityContribution extends Disposable implements IWor } }); } + async run(accessor: ServicesAccessor): Promise { const dialogService = accessor.get(IDialogService); const userDataAutoSyncEnablementService = accessor.get(IUserDataAutoSyncEnablementService); const userDataSyncStoreManagementService = accessor.get(IUserDataSyncStoreManagementService); const storageService = accessor.get(IStorageService); - const askToUseInsidersSettingsSyncService = isSwitchingToInsiders && userDataAutoSyncEnablementService.isEnabled(); - const useInsidersSettingsSyncServiceCheckedKey = 'switchQuality.useInsidersSettingsSyncService.checked'; + const selectSettingsSyncServiceDialogShownKey = 'switchQuality.selectSettingsSyncServiceDialogShown'; + let userDataSyncStoreType: UserDataSyncStoreType | undefined; + if (isSwitchingToInsiders && userDataAutoSyncEnablementService.isEnabled() + && !storageService.getBoolean(selectSettingsSyncServiceDialogShownKey, StorageScope.GLOBAL, false)) { + userDataSyncStoreType = await this.selectSettingsSyncService(dialogService); + if (!userDataSyncStoreType) { + return; + } + } const res = await dialogService.confirm({ type: 'info', - message: askToUseInsidersSettingsSyncService ? nls.localize('relaunchMessage1', "Choose Settings Sync service and Reload") - : nls.localize('relaunchMessage2', "Changing the version requires a reload to take effect"), - detail: isSwitchingToInsiders ? + message: nls.localize('relaunchMessage', "Changing the version requires a reload to take effect"), + detail: newQuality === 'insider' ? nls.localize('relaunchDetailInsiders', "Press the reload button to switch to the nightly pre-production version of VSCode.") : nls.localize('relaunchDetailStable', "Press the reload button to switch to the monthly released stable version of VSCode."), - checkbox: askToUseInsidersSettingsSyncService ? { - label: nls.localize('useInsidersSyncService.description', "Use Insiders Settings Sync service for syncing."), - checked: storageService.getBoolean(useInsidersSettingsSyncServiceCheckedKey, StorageScope.GLOBAL, true) - } : undefined, primaryButton: nls.localize('reload', "&&Reload") }); if (res.confirmed) { - if (askToUseInsidersSettingsSyncService) { - storageService.store(useInsidersSettingsSyncServiceCheckedKey, !!res.checkboxChecked, StorageScope.GLOBAL, StorageTarget.USER); - userDataSyncStoreManagementService.switch(res.checkboxChecked ? 'insiders' : 'stable'); + if (userDataSyncStoreType !== undefined) { + userDataSyncStoreManagementService.set(userDataSyncStoreType); + storageService.store(selectSettingsSyncServiceDialogShownKey, true, StorageScope.GLOBAL, StorageTarget.USER); + await storageService.flush(); } productQualityChangeHandler(newQuality); } } + + private async selectSettingsSyncService(dialogService: IDialogService): Promise { + const res = await dialogService.show( + Severity.Info, + nls.localize('selectSyncService.message', "Choose the settings sync service to use"), + [ + nls.localize('use insiders', "Insiders"), + nls.localize('use stable', "Stable (current)"), + nls.localize('cancel', "Cancel"), + ], + { + detail: nls.localize('selectSyncService.detail', "Switching to insiders version will synchronize your data using insiders settings sync service."), + cancelId: 2 + } + ); + return res.choice === 0 ? 'insiders' : res.choice === 1 ? 'stable' : undefined; + } }); } } From 78bdc620d5e1999bc43254a83d9616799ffe5d95 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 10 Feb 2021 21:05:19 +0100 Subject: [PATCH 005/325] - disable auto sync when default service changed in web - donot prevent turning off sync --- .../common/userDataAutoSyncService.ts | 17 ++++++++++++----- .../userDataSync/browser/userDataSync.ts | 14 +++++++++++++- .../userDataAutoSyncEnablementService.ts | 15 ++++++++------- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts index 0a4a2fded18..246b17bc8fc 100644 --- a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts @@ -18,6 +18,7 @@ import { localize } from 'vs/nls'; import { toLocalISOString } from 'vs/base/common/date'; import { URI } from 'vs/base/common/uri'; import { isEqual } from 'vs/base/common/resources'; +import { isWeb } from 'vs/base/common/platform'; type AutoSyncClassification = { sources: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; @@ -73,9 +74,10 @@ export class UserDataAutoSyncEnablementService extends Disposable implements _IU } setEnablement(enabled: boolean): void { - if (this.canToggleEnablement()) { - this.storageService.store(enablementKey, enabled, StorageScope.GLOBAL, StorageTarget.MACHINE); + if (enabled && !this.canToggleEnablement()) { + return; } + this.storageService.store(enablementKey, enabled, StorageScope.GLOBAL, StorageTarget.MACHINE); } private onDidStorageChange(storageChangeEvent: IStorageValueChangeEvent): void { @@ -313,9 +315,14 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto // Service changed else if (userDataSyncError.code === UserDataSyncErrorCode.ServiceChanged || userDataSyncError.code === UserDataSyncErrorCode.DefaultServiceChanged) { - await this.turnOff(false, true /* force soft turnoff on error */, true /* do not disable machine */); - await this.turnOn(); - this.logService.info('Auto Sync: Sync Service changed. Turned off auto sync, reset local state and turned on auto sync.'); + if (userDataSyncError.code === UserDataSyncErrorCode.DefaultServiceChanged && isWeb) { + await this.turnOff(false, true /* force soft turnoff on error */); + this.logService.info('Auto Sync: Turned off sync because default sync service is changed.'); + } else { + await this.turnOff(false, true /* force soft turnoff on error */, true /* do not disable machine */); + await this.turnOn(); + this.logService.info('Auto Sync: Sync Service changed. Turned off auto sync, reset local state and turned on auto sync.'); + } } else { diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index bd9aadf11d9..071d0f01ff8 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -54,6 +54,7 @@ import { UserDataSyncDataViews } from 'vs/workbench/contrib/userDataSync/browser import { IUserDataSyncWorkbenchService, getSyncAreaLabel, AccountStatus, CONTEXT_SYNC_STATE, CONTEXT_SYNC_ENABLEMENT, CONTEXT_ACCOUNT_STATE, CONFIGURE_SYNC_COMMAND_ID, SHOW_SYNC_LOG_COMMAND_ID, SYNC_VIEW_CONTAINER_ID, SYNC_TITLE, SYNC_VIEW_ICON } from 'vs/workbench/services/userDataSync/common/userDataSync'; import { Codicon } from 'vs/base/common/codicons'; import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer'; +import { isWeb } from 'vs/base/common/platform'; const CONTEXT_CONFLICTS_SOURCES = new RawContextKey('conflictsSources', ''); @@ -288,7 +289,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo case UserDataSyncErrorCode.TurnedOff: this.notificationService.notify({ severity: Severity.Info, - message: localize('turned off', "Settings sync was turned off from another device, please sign in again to turn on sync."), + message: localize('turned off', "Settings sync was turned off from another device, please turn on sync again."), actions: { primary: [new Action('turn on sync', localize('turn on sync', "Turn on Settings Sync..."), undefined, true, () => this.turnOn())] } @@ -323,6 +324,17 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } }); return; + case UserDataSyncErrorCode.DefaultServiceChanged: + if (isEqual(this.userDataSyncStoreManagementService.userDataSyncStore?.url, this.userDataSyncStoreManagementService.userDataSyncStore?.insidersUrl) && isWeb) { + this.notificationService.notify({ + severity: Severity.Info, + message: localize('switched to insiders', "Settings sync was turned off because VSCode Insiders now uses a separate service. Please turn on sync again."), + actions: { + primary: [new Action('turn on sync', localize('turn on sync', "Turn on Settings Sync..."), undefined, true, () => this.turnOn())] + } + }); + } + return; } } diff --git a/src/vs/workbench/services/userDataSync/browser/userDataAutoSyncEnablementService.ts b/src/vs/workbench/services/userDataSync/browser/userDataAutoSyncEnablementService.ts index af14b952ca6..41540b10fc8 100644 --- a/src/vs/workbench/services/userDataSync/browser/userDataAutoSyncEnablementService.ts +++ b/src/vs/workbench/services/userDataSync/browser/userDataAutoSyncEnablementService.ts @@ -29,13 +29,14 @@ export class WebUserDataAutoSyncEnablementService extends UserDataAutoSyncEnable } setEnablement(enabled: boolean) { - if (this.canToggleEnablement()) { - if (this.enabled !== enabled) { - this.enabled = enabled; - super.setEnablement(enabled); - if (this.workbenchEnvironmentService.options?.settingsSyncOptions?.enablementHandler) { - this.workbenchEnvironmentService.options.settingsSyncOptions.enablementHandler(this.enabled); - } + if (enabled && !this.canToggleEnablement()) { + return; + } + if (this.enabled !== enabled) { + this.enabled = enabled; + super.setEnablement(enabled); + if (this.workbenchEnvironmentService.options?.settingsSyncOptions?.enablementHandler) { + this.workbenchEnvironmentService.options.settingsSyncOptions.enablementHandler(this.enabled); } } } From 74b6734e49bd420373380df8cd99ce12da2e7f5c Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 10 Feb 2021 21:14:24 +0100 Subject: [PATCH 006/325] remove web overrides --- src/vs/platform/product/common/productService.ts | 1 - src/vs/platform/userDataSync/common/userDataSyncStoreService.ts | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/vs/platform/product/common/productService.ts b/src/vs/platform/product/common/productService.ts index 92b8c1a6d52..f810e868ca7 100644 --- a/src/vs/platform/product/common/productService.ts +++ b/src/vs/platform/product/common/productService.ts @@ -23,7 +23,6 @@ export interface IBuiltInExtension { } export type ConfigurationSyncStore = { - web?: Partial>, url: string, insidersUrl: string, stableUrl: string, diff --git a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts index a2680a644cb..70dc4859d47 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts @@ -57,8 +57,6 @@ export abstract class AbstractUserDataSyncStoreManagementService extends Disposa } protected toUserDataSyncStore(productStore: ConfigurationSyncStore | undefined, configuredStore?: ConfigurationSyncStore): UserDataSyncStore | undefined { - // Web overrides - productStore = isWeb && productStore?.web ? { ...productStore, ...productStore.web } : productStore; const value: Partial = { ...(productStore || {}), ...(configuredStore || {}) }; if (value && isString(value.url) From 62cbf21904e36f2f58fedaef236d9fc742170e9c Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 10 Feb 2021 21:14:54 +0100 Subject: [PATCH 007/325] update distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 45c7678e9f2..3ebeba5489d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.54.0", - "distro": "f542aeaaf397d5c71e480442fe772dbe362726db", + "distro": "474cec03b7b7f7ea97ffd4d2748ac79a4752ab68", "author": { "name": "Microsoft Corporation" }, From f57bdeab80e15859c24664038ff4273b572f77c3 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 10 Feb 2021 21:20:58 +0100 Subject: [PATCH 008/325] Merge branch 'master' into sandy081/settingsSync/align --- package.json | 2 +- .../browser/ui/actionbar/actionViewItems.ts | 32 +- src/vs/base/browser/ui/actionbar/actionbar.ts | 12 + .../ui/dropdown/dropdownActionViewItem.ts | 1 - .../workspace/common/workspaceTrust.ts | 297 +----------------- .../api/browser/mainThreadAuthentication.ts | 29 +- .../mainThreadFileSystemEventService.ts | 8 +- src/vs/workbench/api/common/extHostTypes.ts | 68 +++- .../api/common/menusExtensionPoint.ts | 5 + .../browser/actions/workspaceActions.ts | 5 +- .../parts/activitybar/activitybarActions.ts | 5 + .../browser/parts/compositeBarActions.ts | 6 - .../browser/parts/editor/breadcrumbsPicker.ts | 10 +- .../debug/browser/debug.contribution.ts | 4 +- .../contrib/debug/browser/replFilter.ts | 4 + .../contrib/debug/common/debugProtocol.d.ts | 7 + .../experimentService.test.ts | 2 +- .../extensionsActions.test.ts | 2 +- .../markers/browser/markersViewActions.ts | 4 + .../contrib/remote/browser/remoteExplorer.ts | 12 +- .../contrib/remote/browser/tunnelView.ts | 29 +- .../search/browser/search.contribution.ts | 9 +- .../contrib/update/browser/update.ts | 16 +- .../browser/workspace.contribution.ts | 52 +-- .../workspaceTrustFileSystemProvider.ts | 2 +- .../browser/authenticationService.ts | 46 +-- .../extensionEnablementService.test.ts | 2 +- .../remote/common/remoteExplorerService.ts | 4 +- .../workspaces/common/workspaceTrust.ts | 290 +++++++++++++++++ .../test/common/testWorkspaceTrustService.ts} | 7 +- .../test/browser/workbenchTestServices.ts | 2 +- yarn.lock | 8 +- 32 files changed, 516 insertions(+), 466 deletions(-) create mode 100644 src/vs/workbench/services/workspaces/common/workspaceTrust.ts rename src/vs/{platform/workspace/test/common/testWorkspaceTrust.ts => workbench/services/workspaces/test/common/testWorkspaceTrustService.ts} (79%) diff --git a/package.json b/package.json index 3ebeba5489d..e6c9f604c56 100644 --- a/package.json +++ b/package.json @@ -195,7 +195,7 @@ "underscore": "^1.8.2", "vinyl": "^2.0.0", "vinyl-fs": "^3.0.0", - "vscode-debugprotocol": "1.44.0", + "vscode-debugprotocol": "1.45.0-pre.0", "vscode-nls-dev": "^3.3.1", "vscode-telemetry-extractor": "^1.6.0", "webpack": "^4.43.0", diff --git a/src/vs/base/browser/ui/actionbar/actionViewItems.ts b/src/vs/base/browser/ui/actionbar/actionViewItems.ts index 0968da8a678..b4dafee88bf 100644 --- a/src/vs/base/browser/ui/actionbar/actionViewItems.ts +++ b/src/vs/base/browser/ui/actionbar/actionViewItems.ts @@ -163,8 +163,11 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem { this.actionRunner.run(this._action, context); } + // Only set the tabIndex on the element once it is about to get focused + // That way this element wont be a tab stop when it is not needed #106441 focus(): void { if (this.element) { + this.element.tabIndex = 0; this.element.focus(); this.element.classList.add('focused'); } @@ -173,10 +176,21 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem { blur(): void { if (this.element) { this.element.blur(); + this.element.tabIndex = -1; this.element.classList.remove('focused'); } } + setFocusable(): void { + if (this.element) { + this.element.tabIndex = 0; + } + } + + get trapsArrowNavigation(): boolean { + return false; + } + protected updateEnabled(): void { // implement in subclass } @@ -259,14 +273,27 @@ export class ActionViewItem extends BaseActionViewItem { this.updateChecked(); } + // Only set the tabIndex on the element once it is about to get focused + // That way this element wont be a tab stop when it is not needed #106441 focus(): void { - super.focus(); - if (this.label) { + this.label.tabIndex = 0; this.label.focus(); } } + blur(): void { + if (this.label) { + this.label.tabIndex = -1; + } + } + + setFocusable(): void { + if (this.label) { + this.label.tabIndex = 0; + } + } + updateLabel(): void { if (this.options.label && this.label) { this.label.textContent = this.getAction().label; @@ -320,7 +347,6 @@ export class ActionViewItem extends BaseActionViewItem { if (this.label) { this.label.removeAttribute('aria-disabled'); this.label.classList.remove('disabled'); - this.label.tabIndex = 0; } if (this.element) { diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index 788a83d553f..b4450cc869f 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -140,6 +140,7 @@ export class ActionBar extends Disposable implements IActionRunner { this._register(DOM.addDisposableListener(this.domNode, DOM.EventType.KEY_DOWN, e => { const event = new StandardKeyboardEvent(e); let eventHandled = true; + const focusedItem = typeof this.focusedItem === 'number' ? this.viewItems[this.focusedItem] : undefined; if (previousKeys && (event.equals(previousKeys[0]) || event.equals(previousKeys[1]))) { eventHandled = this.focusPrevious(); @@ -147,6 +148,12 @@ export class ActionBar extends Disposable implements IActionRunner { eventHandled = this.focusNext(); } else if (event.equals(KeyCode.Escape) && this.cancelHasListener) { this._onDidCancel.fire(); + } else if ((event.equals(KeyCode.Tab) || event.equals(KeyMod.Shift | KeyCode.Tab)) && focusedItem instanceof BaseActionViewItem && focusedItem.trapsArrowNavigation) { + if (event.equals(KeyCode.Tab)) { + this.focusNext(); + } else { + this.focusPrevious(); + } } else if (this.isTriggerKeyEvent(event)) { // Staying out of the else branch even if not triggered if (this._triggerKeys.keyDown) { @@ -294,6 +301,11 @@ export class ActionBar extends Disposable implements IActionRunner { item.setActionContext(this.context); item.render(actionViewItemElement); + if (this.viewItems.every(i => !i.isEnabled()) && item instanceof BaseActionViewItem && item.isEnabled()) { + // We need to allow for the first enabled item to be focused on using tab navigation #106441 + item.setFocusable(); + } + if (index === null || index < 0 || index >= this.actionsList.children.length) { this.actionsList.appendChild(actionViewItemElement); this.viewItems.push(item); diff --git a/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts b/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts index 2a712e089f9..353b766ef1d 100644 --- a/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts +++ b/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts @@ -78,7 +78,6 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem { this.element.classList.add(...classNames); - this.element.tabIndex = 0; this.element.setAttribute('role', 'button'); this.element.setAttribute('aria-haspopup', 'true'); this.element.setAttribute('aria-expanded', 'false'); diff --git a/src/vs/platform/workspace/common/workspaceTrust.ts b/src/vs/platform/workspace/common/workspaceTrust.ts index 1990e310180..56f4fae82dc 100644 --- a/src/vs/platform/workspace/common/workspaceTrust.ts +++ b/src/vs/platform/workspace/common/workspaceTrust.ts @@ -3,19 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Event } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; -import { IWorkspace, IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; - -export const WORKSPACE_TRUST_ENABLED = 'workspace.trustEnabled'; -export const WORKSPACE_TRUST_URI = URI.parse('workspaceTrust:/Trusted Workspaces'); export enum WorkspaceTrustScope { Local = 0, @@ -40,11 +31,6 @@ export function workspaceTrustStateToString(trustState: WorkspaceTrustState) { } } -export const WorkspaceTrustContext = { - PendingRequest: new RawContextKey('workspaceTrustPendingRequest', false), - TrustState: new RawContextKey('workspaceTrustState', WorkspaceTrustState.Unknown) -}; - export interface IWorkspaceTrustModel { readonly onDidChangeTrustState: Event; @@ -86,290 +72,11 @@ export interface IWorkspaceTrustService { getWorkspaceTrustState(): WorkspaceTrustState; isWorkspaceTrustEnabled(): boolean; requireWorkspaceTrust(request: IWorkspaceTrustRequest): Promise; - resetWorkspaceTrust(): Promise; } -interface IWorkspaceTrustStateInfo { +export interface IWorkspaceTrustStateInfo { localFolders: { uri: string, trustState: WorkspaceTrustState }[] // Removing complexity of remote items //trustedRemoteItems: { uri: string }[] } - -export const WORKSPACE_TRUST_STORAGE_KEY = 'content.trust.model.key'; - -export class WorkspaceTrustModel extends Disposable implements IWorkspaceTrustModel { - - private storageKey = WORKSPACE_TRUST_STORAGE_KEY; - private trustStateInfo: IWorkspaceTrustStateInfo; - - private readonly _onDidChangeTrustState = this._register(new Emitter()); - readonly onDidChangeTrustState = this._onDidChangeTrustState.event; - - constructor( - private readonly storageService: IStorageService - ) { - super(); - - this.trustStateInfo = this.loadTrustInfo(); - this._register(this.storageService.onDidChangeValue(changeEvent => { - if (changeEvent.key === this.storageKey) { - this.onDidStorageChange(); - } - })); - } - - private loadTrustInfo(): IWorkspaceTrustStateInfo { - const infoAsString = this.storageService.get(this.storageKey, StorageScope.GLOBAL); - - let result: IWorkspaceTrustStateInfo | undefined; - try { - if (infoAsString) { - result = JSON.parse(infoAsString); - } - } catch { } - - if (!result) { - result = { - localFolders: [], - //trustedRemoteItems: [] - }; - } - - if (!result.localFolders) { - result.localFolders = []; - } - - // if (!result.trustedRemoteItems) { - // result.trustedRemoteItems = []; - // } - - return result; - } - - private saveTrustInfo(): void { - this.storageService.store(this.storageKey, JSON.stringify(this.trustStateInfo), StorageScope.GLOBAL, StorageTarget.MACHINE); - } - - private onDidStorageChange(): void { - this.trustStateInfo = this.loadTrustInfo(); - - this._onDidChangeTrustState.fire(); - } - - setFolderTrustState(folder: URI, trustState: WorkspaceTrustState): void { - let changed = false; - - if (trustState === WorkspaceTrustState.Unknown) { - const before = this.trustStateInfo.localFolders.length; - this.trustStateInfo.localFolders = this.trustStateInfo.localFolders.filter(info => info.uri !== folder.toString()); - - if (this.trustStateInfo.localFolders.length !== before) { - changed = true; - } - } else { - let found = false; - for (const trustInfo of this.trustStateInfo.localFolders) { - if (trustInfo.uri === folder.toString()) { - found = true; - if (trustInfo.trustState !== trustState) { - trustInfo.trustState = trustState; - changed = true; - } - } - } - - if (!found) { - this.trustStateInfo.localFolders.push({ uri: folder.toString(), trustState }); - changed = true; - } - } - - if (changed) { - this.saveTrustInfo(); - } - } - - getFolderTrustState(folder: URI): WorkspaceTrustState { - for (const trustInfo of this.trustStateInfo.localFolders) { - if (trustInfo.uri === folder.toString()) { - return trustInfo.trustState; - } - } - - return WorkspaceTrustState.Unknown; - } -} - -export class WorkspaceTrustRequestModel extends Disposable implements IWorkspaceTrustRequestModel { - trustRequest: IWorkspaceTrustRequest | undefined; - - _onDidInitiateRequest = this._register(new Emitter()); - onDidInitiateRequest: Event = this._onDidInitiateRequest.event; - - _onDidCompleteRequest = this._register(new Emitter()); - onDidCompleteRequest = this._onDidCompleteRequest.event; - - initiateRequest(request: IWorkspaceTrustRequest): void { - if (this.trustRequest && (!request.immediate || this.trustRequest.immediate)) { - return; - } - - this.trustRequest = request; - this._onDidInitiateRequest.fire(); - } - - completeRequest(trustState?: WorkspaceTrustState): void { - this.trustRequest = undefined; - this._onDidCompleteRequest.fire(trustState); - } -} - -export class WorkspaceTrustService extends Disposable implements IWorkspaceTrustService { - - _serviceBrand: undefined; - private readonly dataModel: IWorkspaceTrustModel; - readonly requestModel: IWorkspaceTrustRequestModel; - - private readonly _onDidChangeTrustState = this._register(new Emitter()); - readonly onDidChangeTrustState = this._onDidChangeTrustState.event; - - private _currentTrustState: WorkspaceTrustState = WorkspaceTrustState.Unknown; - private _inFlightResolver?: (trustState: WorkspaceTrustState) => void; - private _trustRequestPromise?: Promise; - private _workspace: IWorkspace; - - private readonly _ctxWorkspaceTrustState: IContextKey; - private readonly _ctxWorkspaceTrustPendingRequest: IContextKey; - - constructor( - @IStorageService private readonly storageService: IStorageService, - @IWorkspaceContextService private readonly workspaceService: IWorkspaceContextService, - @IConfigurationService readonly configurationService: IConfigurationService, - @IContextKeyService readonly contextKeyService: IContextKeyService - ) { - super(); - - this.dataModel = this._register(new WorkspaceTrustModel(this.storageService)); - this.requestModel = this._register(new WorkspaceTrustRequestModel()); - - this._workspace = this.workspaceService.getWorkspace(); - this._currentTrustState = this.calculateWorkspaceTrustState(); - - this._register(this.dataModel.onDidChangeTrustState(() => this.currentTrustState = this.calculateWorkspaceTrustState())); - this._register(this.requestModel.onDidCompleteRequest((trustState) => this.onTrustRequestCompleted(trustState))); - - this._ctxWorkspaceTrustState = WorkspaceTrustContext.TrustState.bindTo(contextKeyService); - this._ctxWorkspaceTrustPendingRequest = WorkspaceTrustContext.PendingRequest.bindTo(contextKeyService); - this._ctxWorkspaceTrustState.set(this.currentTrustState); - } - - private get currentTrustState(): WorkspaceTrustState { - return this._currentTrustState; - } - - private set currentTrustState(trustState: WorkspaceTrustState) { - if (this._currentTrustState === trustState) { return; } - const previousState = this._currentTrustState; - this._currentTrustState = trustState; - - this._onDidChangeTrustState.fire({ previousTrustState: previousState, currentTrustState: this._currentTrustState }); - } - - private calculateWorkspaceTrustState(): WorkspaceTrustState { - if (!this.isWorkspaceTrustEnabled()) { - return WorkspaceTrustState.Trusted; - } - - if (this.workspaceService.getWorkbenchState() === WorkbenchState.EMPTY) { - return WorkspaceTrustState.Trusted; - } - - let state = undefined; - for (const folder of this._workspace.folders) { - const folderTrust = this.dataModel.getFolderTrustState(folder.uri); - - switch (folderTrust) { - case WorkspaceTrustState.Untrusted: - return WorkspaceTrustState.Untrusted; - case WorkspaceTrustState.Unknown: - state = folderTrust; - break; - case WorkspaceTrustState.Trusted: - if (state === undefined) { - state = folderTrust; - } - break; - } - } - - return state ?? WorkspaceTrustState.Unknown; - } - - private onTrustRequestCompleted(trustState?: WorkspaceTrustState): void { - if (this._inFlightResolver) { - this._inFlightResolver(trustState === undefined ? this.currentTrustState : trustState); - } - - this._inFlightResolver = undefined; - this._trustRequestPromise = undefined; - - if (trustState === undefined) { - return; - } - - this._workspace.folders.forEach(folder => { - this.dataModel.setFolderTrustState(folder.uri, trustState); - }); - - this._ctxWorkspaceTrustPendingRequest.set(false); - this._ctxWorkspaceTrustState.set(trustState); - } - - getWorkspaceTrustState(): WorkspaceTrustState { - return this.currentTrustState; - } - - isWorkspaceTrustEnabled(): boolean { - return this.configurationService.getValue(WORKSPACE_TRUST_ENABLED) ?? false; - } - - async requireWorkspaceTrust(request?: IWorkspaceTrustRequest): Promise { - if (this.currentTrustState === WorkspaceTrustState.Trusted) { - return this.currentTrustState; - } - if (this.currentTrustState === WorkspaceTrustState.Untrusted && !request?.immediate) { - return this.currentTrustState; - } - - if (this._trustRequestPromise) { - if (request?.immediate && - this.requestModel.trustRequest && - !this.requestModel.trustRequest.immediate) { - this.requestModel.initiateRequest(request); - } - - return this._trustRequestPromise; - } - - this._trustRequestPromise = new Promise(resolve => { - this._inFlightResolver = resolve; - }); - - this.requestModel.initiateRequest(request); - this._ctxWorkspaceTrustPendingRequest.set(true); - - return this._trustRequestPromise; - } - - async resetWorkspaceTrust(): Promise { - if (this.currentTrustState !== WorkspaceTrustState.Unknown) { - this._workspace.folders.forEach(folder => { - this.dataModel.setFolderTrustState(folder.uri, WorkspaceTrustState.Unknown); - }); - } - return Promise.resolve(WorkspaceTrustState.Unknown); - } -} - -registerSingleton(IWorkspaceTrustService, WorkspaceTrustService); diff --git a/src/vs/workbench/api/browser/mainThreadAuthentication.ts b/src/vs/workbench/api/browser/mainThreadAuthentication.ts index 09009ba5974..e426e5feae5 100644 --- a/src/vs/workbench/api/browser/mainThreadAuthentication.ts +++ b/src/vs/workbench/api/browser/mainThreadAuthentication.ts @@ -21,6 +21,8 @@ export class MainThreadAuthenticationProvider extends Disposable { private _accounts = new Map(); // Map account name to session ids private _sessions = new Map(); // Map account id to name + private _hasInitializedSessions = false; + constructor( private readonly _proxy: ExtHostAuthenticationShape, public readonly id: string, @@ -33,11 +35,6 @@ export class MainThreadAuthenticationProvider extends Disposable { ) { super(); } - - public async initialize(): Promise { - return this.registerCommandsAndContextMenuItems(); - } - public hasSessions(): boolean { return !!this._sessions.size; } @@ -83,15 +80,6 @@ export class MainThreadAuthenticationProvider extends Disposable { quickPick.show(); } - private async registerCommandsAndContextMenuItems(): Promise { - try { - const sessions = await this._proxy.$getSessions(this.id); - sessions.forEach(session => this.registerSession(session)); - } catch (_) { - // Ignore - } - } - private registerSession(session: modes.AuthenticationSession) { this._sessions.set(session.id, session.account.label); @@ -123,7 +111,13 @@ export class MainThreadAuthenticationProvider extends Disposable { } async getSessions(): Promise> { - return this._proxy.$getSessions(this.id); + const sessions = await this._proxy.$getSessions(this.id); + if (!this._hasInitializedSessions) { + sessions.forEach(session => this.registerSession(session)); + this._hasInitializedSessions = true; + } + + return sessions; } async updateSessionItems(event: modes.AuthenticationSessionsChangeEvent): Promise { @@ -195,7 +189,6 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu async $registerAuthenticationProvider(id: string, label: string, supportsMultipleAccounts: boolean): Promise { const provider = new MainThreadAuthenticationProvider(this._proxy, id, label, supportsMultipleAccounts, this.notificationService, this.storageService, this.quickInputService, this.dialogService); - await provider.initialize(); this.authenticationService.registerAuthenticationProvider(id, provider); } @@ -268,7 +261,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu async $getSession(providerId: string, scopes: string[], extensionId: string, extensionName: string, options: { createIfNone: boolean, clearSessionPreference: boolean }): Promise { const orderedScopes = scopes.sort().join(' '); - const sessions = (await this.authenticationService.getSessions(providerId)).filter(session => session.scopes.slice().sort().join(' ') === orderedScopes); + const sessions = (await this.authenticationService.getSessions(providerId, true)).filter(session => session.scopes.slice().sort().join(' ') === orderedScopes); const silent = !options.createIfNone; let session: modes.AuthenticationSession | undefined; @@ -300,7 +293,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu throw new Error('User did not consent to login.'); } - session = await this.authenticationService.login(providerId, scopes); + session = await this.authenticationService.login(providerId, scopes, true); await this.setTrustedExtensionAndAccountPreference(providerId, session.account.label, extensionId, extensionName, session.id); } else { await this.authenticationService.requestNewSession(providerId, scopes, extensionId, extensionName); diff --git a/src/vs/workbench/api/browser/mainThreadFileSystemEventService.ts b/src/vs/workbench/api/browser/mainThreadFileSystemEventService.ts index c03943332e4..2b11030f2e0 100644 --- a/src/vs/workbench/api/browser/mainThreadFileSystemEventService.ts +++ b/src/vs/workbench/api/browser/mainThreadFileSystemEventService.ts @@ -129,13 +129,13 @@ export class MainThreadFileSystemEventService { } } else { if (operation === FileOperation.CREATE) { - message = localize('ask.N.create', "{0} extensions want to make refactoring changes with this file creation", data.extensionNames.length); + message = localize({ key: 'ask.N.create', comment: ['{0} is a number, e.g "3 extensions want..."'] }, "{0} extensions want to make refactoring changes with this file creation", data.extensionNames.length); } else if (operation === FileOperation.COPY) { - message = localize('ask.N.copy', "{0} extensions want to make refactoring changes with this file copy", data.extensionNames.length); + message = localize({ key: 'ask.N.copy', comment: ['{0} is a number, e.g "3 extensions want..."'] }, "{0} extensions want to make refactoring changes with this file copy", data.extensionNames.length); } else if (operation === FileOperation.MOVE) { - message = localize('ask.N.move', "{0} extensions want to make refactoring changes with this file move", data.extensionNames.length); + message = localize({ key: 'ask.N.move', comment: ['{0} is a number, e.g "3 extensions want..."'] }, "{0} extensions want to make refactoring changes with this file move", data.extensionNames.length); } else /* if (operation === FileOperation.DELETE) */ { - message = localize('ask.N.delete', "{0} extensions want to make refactoring changes with this file deletion", data.extensionNames.length); + message = localize({ key: 'ask.N.delete', comment: ['{0} is a number, e.g "3 extensions want..."'] }, "{0} extensions want to make refactoring changes with this file deletion", data.extensionNames.length); } } diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 42aa25ccccd..0ead4e754aa 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -13,7 +13,7 @@ import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import { FileSystemProviderErrorCode, markAsFileSystemProviderError } from 'vs/platform/files/common/files'; import { RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver'; -import { addIdToOutput, CellEditType, ICellEditOperation, ICellOutputEdit, ITransformedDisplayOutputDto, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { addIdToOutput, CellEditType, ICellEditOperation, ICellOutputEdit, ITransformedDisplayOutputDto, notebookDocumentMetadataDefaults, NOTEBOOK_DISPLAY_ORDER } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import type * as vscode from 'vscode'; function es5ClassCompat(target: Function): any { @@ -2813,6 +2813,72 @@ export enum ColorThemeKind { //#region Notebook +export class NotebookCellMetadata { + + constructor( + readonly editable?: boolean, + readonly breakpointMargin?: boolean, + readonly runnable?: boolean, + readonly hasExecutionOrder?: boolean, + readonly executionOrder?: number, + readonly runState?: NotebookCellRunState, + readonly runStartTime?: number, + readonly statusMessage?: string, + readonly lastRunDuration?: number, + readonly inputCollapsed?: boolean, + readonly outputCollapsed?: boolean, + readonly custom?: Record, + ) { } + + with(change: Partial>): NotebookCellMetadata { + return new NotebookCellMetadata( + change.editable ?? this.editable, + change.breakpointMargin ?? this.breakpointMargin, + change.runnable ?? this.runnable, + change.hasExecutionOrder ?? this.hasExecutionOrder, + change.executionOrder ?? this.executionOrder, + change.runState ?? this.runState, + change.runStartTime ?? this.runStartTime, + change.statusMessage ?? this.statusMessage, + change.lastRunDuration ?? this.lastRunDuration, + change.inputCollapsed ?? this.inputCollapsed, + change.outputCollapsed ?? this.outputCollapsed, + change.custom ?? this.custom + ); + } +} + +export class NotebookDocumentMetadata { + + constructor( + readonly editable: boolean = true, + readonly runnable: boolean = true, + readonly cellEditable: boolean = true, + readonly cellRunnable: boolean = true, + readonly cellHasExecutionOrder: boolean = true, + readonly displayOrder: vscode.GlobPattern[] = NOTEBOOK_DISPLAY_ORDER, + readonly custom: { [key: string]: any; } = {}, + readonly runState: NotebookRunState = NotebookRunState.Idle, + readonly trusted: boolean = true, + readonly languages: string[] = [], + ) { } + + with(change: Partial>) { + return new NotebookDocumentMetadata( + change.editable ?? this.editable, + change.runnable ?? this.runnable, + change.cellEditable ?? this.cellEditable, + change.cellRunnable ?? this.cellRunnable, + change.cellHasExecutionOrder ?? this.cellHasExecutionOrder, + change.displayOrder ?? this.displayOrder, + change.custom ?? this.custom, + change.runState ?? this.runState, + change.trusted ?? this.trusted, + change.languages ?? this.languages, + ); + } +} + export class NotebookCellOutputItem { static isNotebookCellOutputItem(obj: unknown): obj is vscode.NotebookCellOutputItem { diff --git a/src/vs/workbench/api/common/menusExtensionPoint.ts b/src/vs/workbench/api/common/menusExtensionPoint.ts index 078eff7442f..6360dadf550 100644 --- a/src/vs/workbench/api/common/menusExtensionPoint.ts +++ b/src/vs/workbench/api/common/menusExtensionPoint.ts @@ -182,6 +182,11 @@ const apiMenus: IAPIMenu[] = [ id: MenuId.TimelineItemContext, description: localize('view.timelineContext', "The Timeline view item context menu") }, + { + key: 'ports/item/context', + id: MenuId.TunnelContext, + description: localize('view.tunnelContext', "The Ports view item context menu") + } ]; namespace schema { diff --git a/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts index 2f1ffb9250b..713e088b96f 100644 --- a/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -23,7 +23,7 @@ import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IWorkspacesService, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; -import { WORKSPACE_TRUST_ENABLED, WORKSPACE_TRUST_URI } from 'vs/platform/workspace/common/workspaceTrust'; +import { WORKSPACE_TRUST_ENABLED, WORKSPACE_TRUST_URI } from 'vs/workbench/services/workspaces/common/workspaceTrust'; export class OpenFileAction extends Action { @@ -255,8 +255,9 @@ class WorkspaceTrustManageAction extends Action2 { constructor() { super({ id: 'workbench.action.manageTrust', - title: { value: nls.localize('resetTrustAction', "Manage Trusted Workspaces"), original: 'Manage Trusted Workspaces' }, + title: { value: nls.localize('manageTrustAction', "Manage Workspace Trust"), original: 'Manage Workspace Trust' }, precondition: ContextKeyExpr.equals(`config.${WORKSPACE_TRUST_ENABLED}`, true), + category: nls.localize('workspacesCategory', "Workspaces"), f1: true, }); } diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 6fa9bb54cdf..7e1fd51d634 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -259,6 +259,11 @@ export class AccountsActivityActionViewItem extends MenuActivityActionViewItem { } }); + if (providers.length && !menus.length) { + const noAccountsAvailableAction = disposables.add(new Action('noAccountsAvailable', localize('noAccounts', "You are not signed in to any accounts"), undefined, false)); + menus.push(noAccountsAvailableAction); + } + if (menus.length && otherCommands.length) { menus.push(disposables.add(new Separator())); } diff --git a/src/vs/workbench/browser/parts/compositeBarActions.ts b/src/vs/workbench/browser/parts/compositeBarActions.ts index 411766b2ea2..c6909901926 100644 --- a/src/vs/workbench/browser/parts/compositeBarActions.ts +++ b/src/vs/workbench/browser/parts/compositeBarActions.ts @@ -199,8 +199,6 @@ export class ActivityActionViewItem extends BaseActionViewItem { this.container = container; - // Make the container tab-able for keyboard navigation - this.container.tabIndex = 0; this.container.setAttribute('role', 'tab'); // Try hard to prevent keyboard only focus feedback when using mouse @@ -647,10 +645,6 @@ export class CompositeActionViewItem extends ActivityActionViewItem { }); } - focus(): void { - this.container.focus(); - } - protected updateChecked(): void { if (this.getAction().checked) { this.container.classList.add('checked'); diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts index 223380e6c52..3b23f21c094 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts @@ -427,15 +427,9 @@ export class BreadcrumbsFilePicker extends BreadcrumbsPicker { } async _revealElement(element: IFileStat | IWorkspaceFolder, options: IEditorOptions, sideBySide: boolean): Promise { - let resource: URI | undefined; - if (isWorkspaceFolder(element)) { - resource = element.uri; - } else if (!element.isDirectory) { - resource = element.resource; - } - if (resource) { + if (!isWorkspaceFolder(element) && element.isFile) { this._onWillPickElement.fire(); - await this._editorService.openEditor({ resource, options }, sideBySide ? SIDE_GROUP : undefined); + await this._editorService.openEditor({ resource: element.resource, options }, sideBySide ? SIDE_GROUP : undefined); return true; } return false; diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index 28086409884..1cc33df05b7 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -20,7 +20,7 @@ import { } from 'vs/workbench/contrib/debug/common/debug'; import { DebugToolBar } from 'vs/workbench/contrib/debug/browser/debugToolBar'; import { DebugService } from 'vs/workbench/contrib/debug/browser/debugService'; -import { registerCommands, ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID, RESTART_LABEL, STEP_INTO_LABEL, STEP_OVER_LABEL, STEP_OUT_LABEL, PAUSE_LABEL, DISCONNECT_LABEL, STOP_LABEL, CONTINUE_LABEL, DEBUG_START_LABEL, DEBUG_START_COMMAND_ID, DEBUG_RUN_LABEL, DEBUG_RUN_COMMAND_ID, EDIT_EXPRESSION_COMMAND_ID, REMOVE_EXPRESSION_COMMAND_ID } from 'vs/workbench/contrib/debug/browser/debugCommands'; +import { registerCommands, ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID, RESTART_LABEL, STEP_INTO_LABEL, STEP_OVER_LABEL, STEP_OUT_LABEL, PAUSE_LABEL, DISCONNECT_LABEL, STOP_LABEL, CONTINUE_LABEL, DEBUG_START_LABEL, DEBUG_START_COMMAND_ID, DEBUG_RUN_LABEL, DEBUG_RUN_COMMAND_ID, EDIT_EXPRESSION_COMMAND_ID, REMOVE_EXPRESSION_COMMAND_ID, SELECT_AND_START_ID, SELECT_AND_START_LABEL } from 'vs/workbench/contrib/debug/browser/debugCommands'; import { StatusBarColorProvider } from 'vs/workbench/contrib/debug/browser/statusbarColorProvider'; import { IViewsRegistry, Extensions as ViewExtensions, IViewContainersRegistry, ViewContainerLocation, ViewContainer } from 'vs/workbench/common/views'; import { isMacintosh, isWeb } from 'vs/base/common/platform'; @@ -123,6 +123,8 @@ function registerCommandsAndActions(): void { registerDebugCommandPaletteItem(TOGGLE_INLINE_BREAKPOINT_ID, nls.localize('inlineBreakpoint', "Inline Breakpoint")); registerDebugCommandPaletteItem(DEBUG_START_COMMAND_ID, DEBUG_START_LABEL, ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Initializing)))); registerDebugCommandPaletteItem(DEBUG_RUN_COMMAND_ID, DEBUG_RUN_LABEL, ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Initializing)))); + registerDebugCommandPaletteItem(SELECT_AND_START_ID, SELECT_AND_START_LABEL, ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Initializing)))); + // Debug callstack context menu const registerDebugViewMenuItem = (menuId: MenuId, id: string, title: string, order: number, when?: ContextKeyExpression, precondition?: ContextKeyExpression, group = 'navigation') => { diff --git a/src/vs/workbench/contrib/debug/browser/replFilter.ts b/src/vs/workbench/contrib/debug/browser/replFilter.ts index 08159fcaebf..668a3f0294b 100644 --- a/src/vs/workbench/contrib/debug/browser/replFilter.ts +++ b/src/vs/workbench/contrib/debug/browser/replFilter.ts @@ -165,6 +165,10 @@ export class ReplFilterActionViewItem extends BaseActionViewItem { return this.filterInputBox.getHistory(); } + get trapsArrowNavigation(): boolean { + return true; + } + private clearFilterText(): void { this.filterInputBox.value = ''; } diff --git a/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts b/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts index dad39a583d7..026c2f48422 100644 --- a/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts +++ b/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts @@ -704,6 +704,7 @@ declare module DebugProtocol { The request configures the debuggers response to thrown exceptions. If an exception is configured to break, a 'stopped' event is fired (with reason 'exception'). Clients should only call this request if the capability 'exceptionBreakpointFilters' returns one or more filters. + If a filter or filter option is invalid (e.g. due to an invalid 'condition'), the request should fail with an 'ErrorResponse' explaining the problem(s). */ export interface SetExceptionBreakpointsRequest extends Request { // command: 'setExceptionBreakpoints'; @@ -1629,10 +1630,14 @@ declare module DebugProtocol { filter: string; /** The name of the filter option. This will be shown in the UI. */ label: string; + /** An optional help text providing additional information about the exception filter. This string is typically shown as a hover and must be translated. */ + description?: string; /** Initial value of the filter option. If not specified a value 'false' is assumed. */ default?: boolean; /** Controls whether a condition can be specified for this filter option. If false or missing, a condition can not be set. */ supportsCondition?: boolean; + /** An optional help text providing information about the condition. This string is shown as the placeholder text for a text box and must be translated. */ + conditionDescription?: string; } /** A structured message object. Used to return errors from requests. */ @@ -1774,6 +1779,8 @@ declare module DebugProtocol { endLine?: number; /** An optional end column of the range covered by the stack frame. */ endColumn?: number; + /** Indicates whether this frame can be restarted with the 'restart' request. Clients should only use this if the debug adapter supports the 'restart' request (capability 'supportsRestartRequest' is true). */ + canRestart?: boolean; /** Optional memory reference for the current instruction pointer in this frame. */ instructionPointerReference?: string; /** The module associated with this frame, if any. */ diff --git a/src/vs/workbench/contrib/experiments/test/electron-browser/experimentService.test.ts b/src/vs/workbench/contrib/experiments/test/electron-browser/experimentService.test.ts index ae6e2d75052..7bdf51aedbb 100644 --- a/src/vs/workbench/contrib/experiments/test/electron-browser/experimentService.test.ts +++ b/src/vs/workbench/contrib/experiments/test/electron-browser/experimentService.test.ts @@ -32,7 +32,7 @@ import { timeout } from 'vs/base/common/async'; import { TestExtensionService } from 'vs/workbench/test/common/workbenchTestServices'; import { OS } from 'vs/base/common/platform'; import { IWorkspaceTrustService } from 'vs/platform/workspace/common/workspaceTrust'; -import { TestWorkspaceTrustService } from 'vs/platform/workspace/test/common/testWorkspaceTrust'; +import { TestWorkspaceTrustService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService'; interface ExperimentSettings { enabled?: boolean; diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts index e93a9c83edf..86b1a268ac9 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts @@ -56,7 +56,7 @@ import { UserDataSyncResourceEnablementService } from 'vs/platform/userDataSync/ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; import { IWorkspaceTrustService } from 'vs/platform/workspace/common/workspaceTrust'; -import { TestWorkspaceTrustService } from 'vs/platform/workspace/test/common/testWorkspaceTrust'; +import { TestWorkspaceTrustService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService'; let instantiationService: TestInstantiationService; let installEvent: Emitter, diff --git a/src/vs/workbench/contrib/markers/browser/markersViewActions.ts b/src/vs/workbench/contrib/markers/browser/markersViewActions.ts index 7dacfc3013c..2a6fc629fe3 100644 --- a/src/vs/workbench/contrib/markers/browser/markersViewActions.ts +++ b/src/vs/workbench/contrib/markers/browser/markersViewActions.ts @@ -283,6 +283,10 @@ export class MarkersFilterActionViewItem extends BaseActionViewItem { } } + get trapsArrowNavigation(): boolean { + return true; + } + private clearFilterText(): void { if (this.filterInputBox) { this.filterInputBox.value = ''; diff --git a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts index 3654be90a53..f3ba2a45148 100644 --- a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts +++ b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts @@ -462,6 +462,7 @@ class OutputAutomaticPortForwarding extends Disposable { class ProcAutomaticPortForwarding extends Disposable { private candidateListener: IDisposable | undefined; private autoForwarded: Set = new Set(); + private notifiedOnly: Set = new Set(); private notifier: OnAutoForwardedAction; private initialCandidates: Set = new Set(); private portsFeatures: IDisposable | undefined; @@ -543,18 +544,18 @@ class ProcAutomaticPortForwarding extends Disposable { if (this.initialCandidates.has(address)) { return undefined; } + const alreadyForwarded = mapHasAddressLocalhostOrAllInterfaces(this.remoteExplorerService.tunnelModel.forwarded, value.host, value.port); if (mapHasAddressLocalhostOrAllInterfaces(this.remoteExplorerService.tunnelModel.detected, value.host, value.port)) { return undefined; } - if (mapHasAddressLocalhostOrAllInterfaces(this.remoteExplorerService.tunnelModel.forwarded, value.host, value.port)) { - return undefined; - } if (this.portsAttributes.getAttributes(value.port)?.onAutoForward === OnPortForward.Ignore) { return undefined; } const forwarded = await this.remoteExplorerService.forward(value, undefined, undefined, undefined, undefined, undefined, false); - if (forwarded) { + if (!alreadyForwarded && forwarded) { this.autoForwarded.add(address); + } else if (forwarded) { + this.notifiedOnly.add(address); } return forwarded; }))).filter(tunnel => !!tunnel); @@ -571,6 +572,9 @@ class ProcAutomaticPortForwarding extends Disposable { this.remoteExplorerService.close(value); this.autoForwarded.delete(key); removedPorts.push(value.port); + } else if (this.notifiedOnly.has(key)) { + this.notifiedOnly.delete(key); + removedPorts.push(value.port); } else if (this.initialCandidates.has(key)) { this.initialCandidates.delete(key); } diff --git a/src/vs/workbench/contrib/remote/browser/tunnelView.ts b/src/vs/workbench/contrib/remote/browser/tunnelView.ts index 53b3382d388..f2808ab0899 100644 --- a/src/vs/workbench/contrib/remote/browser/tunnelView.ts +++ b/src/vs/workbench/contrib/remote/browser/tunnelView.ts @@ -812,23 +812,26 @@ namespace LabelTunnelAction { export const LABEL = nls.localize('remote.tunnel.label', "Set Label"); export function handler(): ICommandHandler { - return async (accessor, arg) => { + return async (accessor, arg): Promise<{ port: number, label: string } | undefined> => { const context = (arg !== undefined || arg instanceof TunnelItem) ? arg : accessor.get(IContextKeyService).getContextKeyValue(TunnelViewSelectionKeyName); if (context instanceof TunnelItem) { - const remoteExplorerService = accessor.get(IRemoteExplorerService); - remoteExplorerService.setEditable(context, { - onFinish: async (value, success) => { - if (success) { - remoteExplorerService.tunnelModel.name(context.remoteHost, context.remotePort, value); - } - remoteExplorerService.setEditable(context, null); - }, - validationMessage: () => null, - placeholder: nls.localize('remote.tunnelsView.labelPlaceholder', "Port label"), - startingValue: context.name + return new Promise(resolve => { + const remoteExplorerService = accessor.get(IRemoteExplorerService); + remoteExplorerService.setEditable(context, { + onFinish: async (value, success) => { + if (success) { + remoteExplorerService.tunnelModel.name(context.remoteHost, context.remotePort, value); + } + remoteExplorerService.setEditable(context, null); + resolve(success ? { port: context.remotePort, label: value } : undefined); + }, + validationMessage: () => null, + placeholder: nls.localize('remote.tunnelsView.labelPlaceholder', "Port label"), + startingValue: context.name + }); }); } - return; + return undefined; }; } } diff --git a/src/vs/workbench/contrib/search/browser/search.contribution.ts b/src/vs/workbench/contrib/search/browser/search.contribution.ts index 30ff0488871..aa467b2a8b6 100644 --- a/src/vs/workbench/contrib/search/browser/search.contribution.ts +++ b/src/vs/workbench/contrib/search/browser/search.contribution.ts @@ -17,7 +17,7 @@ import { Action2, ICommandAction, MenuId, MenuRegistry, registerAction2, SyncAct import { CommandsRegistry, ICommandHandler, ICommandService } from 'vs/platform/commands/common/commands'; import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ConfigurationScope, Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; -import { ContextKeyRegexExpr, ContextKeyEqualsExpr, ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyEqualsExpr, ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IFileService } from 'vs/platform/files/common/files'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; @@ -637,10 +637,6 @@ const viewDescriptor: IViewDescriptor = { mnemonicTitle: nls.localize({ key: 'miViewSearch', comment: ['&& denotes a mnemonic'] }, "&&Search"), keybindings: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_F, - // View: Show Search is used for the keybindings in the View menu and the sidebar, but Find In Files should run the actual action. - // If the context key is clearly false (ContextKeyFalseExpression), the keybinding won't appear. Instead we use a regex that never is true. - // See #116188, #115556, #115511 - when: ContextKeyRegexExpr.create(`never`, /(?!x)x/), }, order: 1 } @@ -714,7 +710,8 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ ] }, id: Constants.FindInFilesActionId, - weight: KeybindingWeight.WorkbenchContrib, + // Give more weightage to this keybinding than of `View: Show Search` keybinding. See #116188, #115556, #115511 + weight: KeybindingWeight.WorkbenchContrib + 1, when: null, primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_F, handler: FindInFilesCommand diff --git a/src/vs/workbench/contrib/update/browser/update.ts b/src/vs/workbench/contrib/update/browser/update.ts index ec779434d7e..7364de67b67 100644 --- a/src/vs/workbench/contrib/update/browser/update.ts +++ b/src/vs/workbench/contrib/update/browser/update.ts @@ -436,7 +436,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu private registerGlobalActivityActions(): void { CommandsRegistry.registerCommand('update.check', () => this.updateService.checkForUpdates(this.environmentService.sessionId)); MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { - group: '6_update', + group: '7_update', command: { id: 'update.check', title: nls.localize('checkForUpdates', "Check for Updates...") @@ -446,7 +446,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu CommandsRegistry.registerCommand('update.checking', () => { }); MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { - group: '6_update', + group: '7_update', command: { id: 'update.checking', title: nls.localize('checkingForUpdates', "Checking for Updates..."), @@ -457,7 +457,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu CommandsRegistry.registerCommand('update.downloadNow', () => this.updateService.downloadUpdate()); MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { - group: '6_update', + group: '7_update', command: { id: 'update.downloadNow', title: nls.localize('download update_1', "Download Update (1)") @@ -467,7 +467,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu CommandsRegistry.registerCommand('update.downloading', () => { }); MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { - group: '6_update', + group: '7_update', command: { id: 'update.downloading', title: nls.localize('DownloadingUpdate', "Downloading Update..."), @@ -478,7 +478,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu CommandsRegistry.registerCommand('update.install', () => this.updateService.applyUpdate()); MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { - group: '6_update', + group: '7_update', command: { id: 'update.install', title: nls.localize('installUpdate...', "Install Update... (1)") @@ -488,7 +488,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu CommandsRegistry.registerCommand('update.updating', () => { }); MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { - group: '6_update', + group: '7_update', command: { id: 'update.updating', title: nls.localize('installingUpdate', "Installing Update..."), @@ -499,7 +499,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu CommandsRegistry.registerCommand('update.restart', () => this.updateService.quitAndInstall()); MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { - group: '6_update', + group: '7_update', command: { id: 'update.restart', title: nls.localize('restartToUpdate', "Restart to Update (1)") @@ -536,7 +536,7 @@ export class SwitchProductQualityContribution extends Disposable implements IWor menu: { id: MenuId.GlobalActivity, when: IsWebContext, - group: '6_update', + group: '7_update', } }); } diff --git a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts index 20bba461f0a..2296cc5f8cd 100644 --- a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts +++ b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts @@ -10,7 +10,7 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { Severity } from 'vs/platform/notification/common/notification'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IWorkspaceTrustService, WorkspaceTrustContext, WORKSPACE_TRUST_ENABLED, WORKSPACE_TRUST_URI, WorkspaceTrustState, WorkspaceTrustStateChangeEvent, workspaceTrustStateToString } from 'vs/platform/workspace/common/workspaceTrust'; +import { IWorkspaceTrustService, WorkspaceTrustState, WorkspaceTrustStateChangeEvent, workspaceTrustStateToString } from 'vs/platform/workspace/common/workspaceTrust'; import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { IActivityService, IconBadge } from 'vs/workbench/services/activity/common/activity'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; @@ -20,11 +20,11 @@ import { ThemeColor } from 'vs/workbench/api/common/extHostTypes'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { WorkspaceTrustFileSystemProvider } from 'vs/workbench/contrib/workspace/common/workspaceTrustFileSystemProvider'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { WorkbenchStateContext } from 'vs/workbench/browser/contextkeys'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from 'vs/workbench/services/statusbar/common/statusbar'; +import { WorkspaceTrustContext, WORKSPACE_TRUST_ENABLED, WORKSPACE_TRUST_URI } from 'vs/workbench/services/workspaces/common/workspaceTrust'; const workspaceTrustIcon = registerIcon('workspace-trust-icon', Codicon.shield, localize('workspaceTrustIcon', "Icon for workspace trust badge.")); @@ -200,7 +200,7 @@ registerAction2(class extends Action2 { menu: { id: MenuId.GlobalActivity, when: WorkspaceTrustContext.PendingRequest, - group: '7_trust', + group: '6_workspace_trust', order: 10 }, }); @@ -240,7 +240,7 @@ registerAction2(class extends Action2 { menu: { id: MenuId.GlobalActivity, when: WorkspaceTrustContext.PendingRequest, - group: '7_trust', + group: '6_workspace_trust', order: 20 }, }); @@ -264,53 +264,19 @@ registerAction2(class extends Action2 { } }); -// Reset Workspace Trust -registerAction2(class extends Action2 { - constructor() { - super({ - id: 'workbench.trust.reset', - title: { - original: 'Reset Workspace Trust', - value: localize('reset', "Reset Workspace Trust") - }, - category: localize('workspacesCategory', "Workspaces"), - f1: true, - precondition: ContextKeyExpr.and(WorkbenchStateContext.isEqualTo('empty').negate(), WorkspaceTrustContext.TrustState.isEqualTo(WorkspaceTrustState.Unknown).negate()) - }); - } - - async run(accessor: ServicesAccessor) { - const dialogService = accessor.get(IDialogService); - const workspaceTrustService = accessor.get(IWorkspaceTrustService); - - const result = await dialogService.confirm({ - message: localize('reset', "Reset Workspace Trust"), - detail: localize('confirmResetWorkspaceTrust', "Resetting workspace trust to the workspace will disable features that may pose a security risk if the contents of the workspace cannot be trusted. Are you sure you want to reset trust this workspace?"), - primaryButton: localize('yesGrant', 'Yes'), - secondaryButton: localize('noGrant', 'No') - }); - - if (result.confirmed) { - workspaceTrustService.resetWorkspaceTrust(); - } - - return; - } -}); - // Manage Workspace Trust registerAction2(class extends Action2 { constructor() { super({ id: 'workbench.trust.manage', title: { - original: 'Manage Trusted Workspaces', - value: localize('manageWorkspaceTrust', "Manage Trusted Workspaces") + original: 'Manage Workspace Trust', + value: localize('manageWorkspaceTrust', "Manage Workspace Trust") }, category: localize('workspacesCategory', "Workspaces"), menu: { id: MenuId.GlobalActivity, - group: '7_trust', + group: '6_workspace_trust', order: 40, when: ContextKeyExpr.and(ContextKeyExpr.equals(`config.${WORKSPACE_TRUST_ENABLED}`, true), WorkspaceTrustContext.PendingRequest.negate()) }, @@ -327,9 +293,9 @@ registerAction2(class extends Action2 { MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { command: { id: 'workbench.trust.manage', - title: localize('manageWorkspaceTrustPending', "Manage Trusted Workspaces (1)"), + title: localize('manageWorkspaceTrustPending', "Manage Workspace Trust (1)"), }, - group: '7_trust', + group: '6_workspace_trust', order: 40, when: ContextKeyExpr.and(ContextKeyExpr.equals(`config.${WORKSPACE_TRUST_ENABLED}`, true), WorkspaceTrustContext.PendingRequest) }); diff --git a/src/vs/workbench/contrib/workspace/common/workspaceTrustFileSystemProvider.ts b/src/vs/workbench/contrib/workspace/common/workspaceTrustFileSystemProvider.ts index 8964edd181b..4c4c49f9480 100644 --- a/src/vs/workbench/contrib/workspace/common/workspaceTrustFileSystemProvider.ts +++ b/src/vs/workbench/contrib/workspace/common/workspaceTrustFileSystemProvider.ts @@ -10,7 +10,7 @@ import { FileDeleteOptions, FileOverwriteOptions, FileSystemProviderCapabilities import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { VSBuffer } from 'vs/base/common/buffer'; -import { WORKSPACE_TRUST_STORAGE_KEY } from 'vs/platform/workspace/common/workspaceTrust'; +import { WORKSPACE_TRUST_STORAGE_KEY } from 'vs/workbench/services/workspaces/common/workspaceTrust'; const WORKSPACE_TRUST_SCHEMA = 'workspaceTrust'; diff --git a/src/vs/workbench/services/authentication/browser/authenticationService.ts b/src/vs/workbench/services/authentication/browser/authenticationService.ts index 2c97d497e03..a77ecf9c238 100644 --- a/src/vs/workbench/services/authentication/browser/authenticationService.ts +++ b/src/vs/workbench/services/authentication/browser/authenticationService.ts @@ -22,7 +22,7 @@ import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/exte import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { flatten } from 'vs/base/common/arrays'; import { isFalsyOrWhitespace } from 'vs/base/common/strings'; -import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { ActivationKind, IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { Severity } from 'vs/platform/notification/common/notification'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; @@ -124,10 +124,10 @@ export interface IAuthenticationService { declaredProviders: AuthenticationProviderInformation[]; readonly onDidChangeDeclaredProviders: Event; - getSessions(providerId: string): Promise>; + getSessions(providerId: string, activateImmediate?: boolean): Promise>; getLabel(providerId: string): string; supportsMultipleAccounts(providerId: string): boolean; - login(providerId: string, scopes: string[]): Promise; + login(providerId: string, scopes: string[], activateImmediate?: boolean): Promise; logout(providerId: string, sessionId: string): Promise; manageTrustedExtensionsForAccount(providerId: string, accountName: string): Promise; @@ -192,7 +192,6 @@ const authenticationExtPoint = ExtensionsRegistry.registerExtensionPoint(); private _sessionAccessRequestItems = new Map(); private _accountBadgeDisposable = this._register(new MutableDisposable()); @@ -278,29 +277,6 @@ export class AuthenticationService extends Disposable implements IAuthentication return this._authenticationProviders.has(id); } - private updateAccountsMenuItem(): void { - let hasSession = false; - this._authenticationProviders.forEach(async provider => { - hasSession = hasSession || provider.hasSessions(); - }); - - if (hasSession && this._noAccountsMenuItem) { - this._noAccountsMenuItem.dispose(); - this._noAccountsMenuItem = undefined; - } - - if (!hasSession && !this._noAccountsMenuItem) { - this._noAccountsMenuItem = MenuRegistry.appendMenuItem(MenuId.AccountsContext, { - group: '0_accounts', - command: { - id: 'noAccounts', - title: nls.localize('noAccounts', "You are not signed in to any accounts"), - precondition: ContextKeyExpr.false() - }, - }); - } - } - registerAuthenticationProvider(id: string, authenticationProvider: MainThreadAuthenticationProvider): void { this._authenticationProviders.set(id, authenticationProvider); this._onDidRegisterAuthenticationProvider.fire({ id, label: authenticationProvider.label }); @@ -309,8 +285,6 @@ export class AuthenticationService extends Disposable implements IAuthentication this._placeholderMenuItem.dispose(); this._placeholderMenuItem = undefined; } - - this.updateAccountsMenuItem(); } unregisterAuthenticationProvider(id: string): void { @@ -319,7 +293,6 @@ export class AuthenticationService extends Disposable implements IAuthentication provider.dispose(); this._authenticationProviders.delete(id); this._onDidUnregisterAuthenticationProvider.fire({ id, label: provider.label }); - this.updateAccountsMenuItem(); const accessRequests = this._sessionAccessRequestItems.get(id) || {}; Object.keys(accessRequests).forEach(extensionId => { @@ -343,7 +316,6 @@ export class AuthenticationService extends Disposable implements IAuthentication if (provider) { this._onDidChangeSessions.fire({ providerId: id, label: provider.label, event: event }); await provider.updateSessionItems(event); - this.updateAccountsMenuItem(); if (event.added) { await this.updateNewSessionRequests(provider); @@ -693,8 +665,8 @@ export class AuthenticationService extends Disposable implements IAuthentication } } - private async tryActivateProvider(providerId: string): Promise { - await this.extensionService.activateByEvent(getAuthenticationProviderActivationEvent(providerId)); + private async tryActivateProvider(providerId: string, activateImmediate: boolean): Promise { + await this.extensionService.activateByEvent(getAuthenticationProviderActivationEvent(providerId), activateImmediate ? ActivationKind.Immediate : ActivationKind.Normal); let provider = this._authenticationProviders.get(providerId); if (provider) { return provider; @@ -724,18 +696,18 @@ export class AuthenticationService extends Disposable implements IAuthentication return Promise.race([didRegister, didTimeout]); } - async getSessions(id: string): Promise> { + async getSessions(id: string, activateImmediate: boolean = false): Promise> { try { - const authProvider = this._authenticationProviders.get(id) || await this.tryActivateProvider(id); + const authProvider = this._authenticationProviders.get(id) || await this.tryActivateProvider(id, activateImmediate); return await authProvider.getSessions(); } catch (_) { throw new Error(`No authentication provider '${id}' is currently registered.`); } } - async login(id: string, scopes: string[]): Promise { + async login(id: string, scopes: string[], activateImmediate: boolean = false): Promise { try { - const authProvider = this._authenticationProviders.get(id) || await this.tryActivateProvider(id); + const authProvider = this._authenticationProviders.get(id) || await this.tryActivateProvider(id, activateImmediate); return await authProvider.login(scopes); } catch (_) { throw new Error(`No authentication provider '${id}' is currently registered.`); diff --git a/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts b/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts index c0ea3e9bf35..671e7fe0afe 100644 --- a/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts +++ b/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts @@ -31,7 +31,7 @@ import { IHostService } from 'vs/workbench/services/host/browser/host'; import { mock } from 'vs/base/test/common/mock'; import { IExtensionBisectService } from 'vs/workbench/services/extensionManagement/browser/extensionBisect'; import { IWorkspaceTrustService } from 'vs/platform/workspace/common/workspaceTrust'; -import { TestWorkspaceTrustService } from 'vs/platform/workspace/test/common/testWorkspaceTrust'; +import { TestWorkspaceTrustService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService'; function createStorageService(instantiationService: TestInstantiationService): IStorageService { let service = instantiationService.get(IStorageService); diff --git a/src/vs/workbench/services/remote/common/remoteExplorerService.ts b/src/vs/workbench/services/remote/common/remoteExplorerService.ts index 68d6939a1b0..24cac4ab5c0 100644 --- a/src/vs/workbench/services/remote/common/remoteExplorerService.ts +++ b/src/vs/workbench/services/remote/common/remoteExplorerService.ts @@ -371,7 +371,9 @@ export class TunnelModel extends Disposable { return tunnel; } } else { - existingTunnel.name = name; + if (name) { + existingTunnel.name = name; + } this._onForwardPort.fire(); return mapHasAddressLocalhostOrAllInterfaces(this.remoteTunnels, remote.host, remote.port); } diff --git a/src/vs/workbench/services/workspaces/common/workspaceTrust.ts b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts new file mode 100644 index 00000000000..daff0ecda29 --- /dev/null +++ b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts @@ -0,0 +1,290 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Emitter, Event } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { URI } from 'vs/base/common/uri'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; +import { IWorkspace, IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceTrustModel, IWorkspaceTrustRequest, IWorkspaceTrustRequestModel, IWorkspaceTrustService, IWorkspaceTrustStateInfo, WorkspaceTrustState, WorkspaceTrustStateChangeEvent } from 'vs/platform/workspace/common/workspaceTrust'; + +export const WORKSPACE_TRUST_ENABLED = 'workspace.trustEnabled'; +export const WORKSPACE_TRUST_STORAGE_KEY = 'content.trust.model.key'; +export const WORKSPACE_TRUST_URI = URI.parse('workspaceTrust:/Trusted Workspaces'); + +export const WorkspaceTrustContext = { + PendingRequest: new RawContextKey('workspaceTrustPendingRequest', false), + TrustState: new RawContextKey('workspaceTrustState', WorkspaceTrustState.Unknown) +}; + +export class WorkspaceTrustModel extends Disposable implements IWorkspaceTrustModel { + + private storageKey = WORKSPACE_TRUST_STORAGE_KEY; + private trustStateInfo: IWorkspaceTrustStateInfo; + + private readonly _onDidChangeTrustState = this._register(new Emitter()); + readonly onDidChangeTrustState = this._onDidChangeTrustState.event; + + constructor( + private readonly storageService: IStorageService + ) { + super(); + + this.trustStateInfo = this.loadTrustInfo(); + this._register(this.storageService.onDidChangeValue(changeEvent => { + if (changeEvent.key === this.storageKey) { + this.onDidStorageChange(); + } + })); + } + + private loadTrustInfo(): IWorkspaceTrustStateInfo { + const infoAsString = this.storageService.get(this.storageKey, StorageScope.GLOBAL); + + let result: IWorkspaceTrustStateInfo | undefined; + try { + if (infoAsString) { + result = JSON.parse(infoAsString); + } + } catch { } + + if (!result) { + result = { + localFolders: [], + //trustedRemoteItems: [] + }; + } + + if (!result.localFolders) { + result.localFolders = []; + } + + // if (!result.trustedRemoteItems) { + // result.trustedRemoteItems = []; + // } + + return result; + } + + private saveTrustInfo(): void { + this.storageService.store(this.storageKey, JSON.stringify(this.trustStateInfo), StorageScope.GLOBAL, StorageTarget.MACHINE); + } + + private onDidStorageChange(): void { + this.trustStateInfo = this.loadTrustInfo(); + + this._onDidChangeTrustState.fire(); + } + + setFolderTrustState(folder: URI, trustState: WorkspaceTrustState): void { + let changed = false; + + if (trustState === WorkspaceTrustState.Unknown) { + const before = this.trustStateInfo.localFolders.length; + this.trustStateInfo.localFolders = this.trustStateInfo.localFolders.filter(info => info.uri !== folder.toString()); + + if (this.trustStateInfo.localFolders.length !== before) { + changed = true; + } + } else { + let found = false; + for (const trustInfo of this.trustStateInfo.localFolders) { + if (trustInfo.uri === folder.toString()) { + found = true; + if (trustInfo.trustState !== trustState) { + trustInfo.trustState = trustState; + changed = true; + } + } + } + + if (!found) { + this.trustStateInfo.localFolders.push({ uri: folder.toString(), trustState }); + changed = true; + } + } + + if (changed) { + this.saveTrustInfo(); + } + } + + getFolderTrustState(folder: URI): WorkspaceTrustState { + for (const trustInfo of this.trustStateInfo.localFolders) { + if (trustInfo.uri === folder.toString()) { + return trustInfo.trustState; + } + } + + return WorkspaceTrustState.Unknown; + } +} + +export class WorkspaceTrustRequestModel extends Disposable implements IWorkspaceTrustRequestModel { + trustRequest: IWorkspaceTrustRequest | undefined; + + private readonly _onDidInitiateRequest = this._register(new Emitter()); + readonly onDidInitiateRequest: Event = this._onDidInitiateRequest.event; + + private readonly _onDidCompleteRequest = this._register(new Emitter()); + readonly onDidCompleteRequest = this._onDidCompleteRequest.event; + + initiateRequest(request: IWorkspaceTrustRequest): void { + if (this.trustRequest && (!request.immediate || this.trustRequest.immediate)) { + return; + } + + this.trustRequest = request; + this._onDidInitiateRequest.fire(); + } + + completeRequest(trustState?: WorkspaceTrustState): void { + this.trustRequest = undefined; + this._onDidCompleteRequest.fire(trustState); + } +} + +export class WorkspaceTrustService extends Disposable implements IWorkspaceTrustService { + + _serviceBrand: undefined; + private readonly dataModel: IWorkspaceTrustModel; + readonly requestModel: IWorkspaceTrustRequestModel; + + private readonly _onDidChangeTrustState = this._register(new Emitter()); + readonly onDidChangeTrustState = this._onDidChangeTrustState.event; + + private _currentTrustState: WorkspaceTrustState = WorkspaceTrustState.Unknown; + private _inFlightResolver?: (trustState: WorkspaceTrustState) => void; + private _trustRequestPromise?: Promise; + private _workspace: IWorkspace; + + private readonly _ctxWorkspaceTrustState: IContextKey; + private readonly _ctxWorkspaceTrustPendingRequest: IContextKey; + + constructor( + @IConfigurationService readonly configurationService: IConfigurationService, + @IContextKeyService readonly contextKeyService: IContextKeyService, + @IStorageService private readonly storageService: IStorageService, + @IWorkspaceContextService private readonly workspaceService: IWorkspaceContextService, + ) { + super(); + + this.dataModel = this._register(new WorkspaceTrustModel(this.storageService)); + this.requestModel = this._register(new WorkspaceTrustRequestModel()); + + this._workspace = this.workspaceService.getWorkspace(); + this._currentTrustState = this.calculateWorkspaceTrustState(); + + this._register(this.dataModel.onDidChangeTrustState(() => this.currentTrustState = this.calculateWorkspaceTrustState())); + this._register(this.requestModel.onDidCompleteRequest((trustState) => this.onTrustRequestCompleted(trustState))); + + this._ctxWorkspaceTrustState = WorkspaceTrustContext.TrustState.bindTo(contextKeyService); + this._ctxWorkspaceTrustPendingRequest = WorkspaceTrustContext.PendingRequest.bindTo(contextKeyService); + this._ctxWorkspaceTrustState.set(this.currentTrustState); + } + + private get currentTrustState(): WorkspaceTrustState { + return this._currentTrustState; + } + + private set currentTrustState(trustState: WorkspaceTrustState) { + if (this._currentTrustState === trustState) { return; } + const previousState = this._currentTrustState; + this._currentTrustState = trustState; + + this._onDidChangeTrustState.fire({ previousTrustState: previousState, currentTrustState: this._currentTrustState }); + } + + private calculateWorkspaceTrustState(): WorkspaceTrustState { + if (!this.isWorkspaceTrustEnabled()) { + return WorkspaceTrustState.Trusted; + } + + if (this.workspaceService.getWorkbenchState() === WorkbenchState.EMPTY) { + return WorkspaceTrustState.Trusted; + } + + let state = undefined; + for (const folder of this._workspace.folders) { + const folderTrust = this.dataModel.getFolderTrustState(folder.uri); + + switch (folderTrust) { + case WorkspaceTrustState.Untrusted: + return WorkspaceTrustState.Untrusted; + case WorkspaceTrustState.Unknown: + state = folderTrust; + break; + case WorkspaceTrustState.Trusted: + if (state === undefined) { + state = folderTrust; + } + break; + } + } + + return state ?? WorkspaceTrustState.Unknown; + } + + private onTrustRequestCompleted(trustState?: WorkspaceTrustState): void { + if (this._inFlightResolver) { + this._inFlightResolver(trustState === undefined ? this.currentTrustState : trustState); + } + + this._inFlightResolver = undefined; + this._trustRequestPromise = undefined; + + if (trustState === undefined) { + return; + } + + this._workspace.folders.forEach(folder => { + this.dataModel.setFolderTrustState(folder.uri, trustState); + }); + + this._ctxWorkspaceTrustPendingRequest.set(false); + this._ctxWorkspaceTrustState.set(trustState); + } + + getWorkspaceTrustState(): WorkspaceTrustState { + return this.currentTrustState; + } + + isWorkspaceTrustEnabled(): boolean { + return this.configurationService.getValue(WORKSPACE_TRUST_ENABLED) ?? false; + } + + async requireWorkspaceTrust(request?: IWorkspaceTrustRequest): Promise { + if (this.currentTrustState === WorkspaceTrustState.Trusted) { + return this.currentTrustState; + } + if (this.currentTrustState === WorkspaceTrustState.Untrusted && !request?.immediate) { + return this.currentTrustState; + } + + if (this._trustRequestPromise) { + if (request?.immediate && + this.requestModel.trustRequest && + !this.requestModel.trustRequest.immediate) { + this.requestModel.initiateRequest(request); + } + + return this._trustRequestPromise; + } + + this._trustRequestPromise = new Promise(resolve => { + this._inFlightResolver = resolve; + }); + + this.requestModel.initiateRequest(request); + this._ctxWorkspaceTrustPendingRequest.set(true); + + return this._trustRequestPromise; + } +} + +registerSingleton(IWorkspaceTrustService, WorkspaceTrustService); diff --git a/src/vs/platform/workspace/test/common/testWorkspaceTrust.ts b/src/vs/workbench/services/workspaces/test/common/testWorkspaceTrustService.ts similarity index 79% rename from src/vs/platform/workspace/test/common/testWorkspaceTrust.ts rename to src/vs/workbench/services/workspaces/test/common/testWorkspaceTrustService.ts index f7a189af2b6..2afa1277f07 100644 --- a/src/vs/platform/workspace/test/common/testWorkspaceTrust.ts +++ b/src/vs/workbench/services/workspaces/test/common/testWorkspaceTrustService.ts @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from 'vs/base/common/event'; -import { IWorkspaceTrustRequest, IWorkspaceTrustRequestModel, IWorkspaceTrustService, WorkspaceTrustChangeEvent, WorkspaceTrustRequestModel, WorkspaceTrustState } from 'vs/platform/workspace/common/workspaceTrust'; +import { IWorkspaceTrustRequest, IWorkspaceTrustRequestModel, IWorkspaceTrustService, WorkspaceTrustChangeEvent, WorkspaceTrustState } from 'vs/platform/workspace/common/workspaceTrust'; +import { WorkspaceTrustRequestModel } from 'vs/workbench/services/workspaces/common/workspaceTrust'; export class TestWorkspaceTrustService implements IWorkspaceTrustService { _serviceBrand: undefined; @@ -24,8 +25,4 @@ export class TestWorkspaceTrustService implements IWorkspaceTrustService { requireWorkspaceTrust(request: IWorkspaceTrustRequest): Promise { return Promise.resolve(WorkspaceTrustState.Trusted); } - - resetWorkspaceTrust(): Promise { - return Promise.resolve(WorkspaceTrustState.Unknown); - } } diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index 30c54d04952..e2d267e6704 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -125,7 +125,7 @@ import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/u import { SideBySideEditor } from 'vs/workbench/browser/parts/editor/sideBySideEditor'; import { IEnterWorkspaceResult, IRecent, IRecentlyOpened, IWorkspaceFolderCreationData, IWorkspaceIdentifier, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { IWorkspaceTrustService } from 'vs/platform/workspace/common/workspaceTrust'; -import { TestWorkspaceTrustService } from 'vs/platform/workspace/test/common/testWorkspaceTrust'; +import { TestWorkspaceTrustService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService'; export function createFileEditorInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput { return instantiationService.createInstance(FileEditorInput, resource, undefined, undefined, undefined, undefined, undefined); diff --git a/yarn.lock b/yarn.lock index 8559099a526..b8177d34186 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10074,10 +10074,10 @@ vm-browserify@^1.0.1: resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== -vscode-debugprotocol@1.44.0: - version "1.44.0" - resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.44.0.tgz#79d11844f908cc5104afc303b3780ad2e5fd486a" - integrity sha512-qf+eBnrDyR2MpP08y1JfzJnFZGHdkk86+SRGRp0XepDGNA6n/Nann5XhtAzdGX/yaZokjTAINK313S2yYhHoPQ== +vscode-debugprotocol@1.45.0-pre.0: + version "1.45.0-pre.0" + resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.45.0-pre.0.tgz#7ea4c6e84d966e96a8398241e46bdf98e0dacfde" + integrity sha512-q0ivFfnjFQyL4Qyxp1K8gSdTpfcvlCxmys5adLydBef1XvDKZNONAKalCZZCyaG/vtOlbV1ma6hS5eALNaLd8w== vscode-nls-dev@^3.3.1: version "3.3.1" From 6896ec35ff9b55fb8877d9e713068e537865d204 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Wed, 10 Feb 2021 21:25:59 -0800 Subject: [PATCH 009/325] Make cell focus indicator more noticeable in large cells --- .../notebook/browser/media/notebook.css | 27 +++++++++++++++++++ .../notebook/browser/notebookBrowser.ts | 1 + .../notebook/browser/notebookEditorWidget.ts | 5 +++- .../browser/view/renderers/cellRenderer.ts | 6 +++-- .../browser/viewModel/codeCellViewModel.ts | 2 +- 5 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/media/notebook.css b/src/vs/workbench/contrib/notebook/browser/media/notebook.css index 84b8e680814..0e4681123ff 100644 --- a/src/vs/workbench/contrib/notebook/browser/media/notebook.css +++ b/src/vs/workbench/contrib/notebook/browser/media/notebook.css @@ -281,27 +281,54 @@ height: 1px; } +.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-left:before, +.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-right:before { + content: ""; + position: absolute; + width: 1px; + height: 100%; +} + /* top border */ .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-top:before, .monaco-workbench .notebookOverlay .monaco-list .markdown-cell-row.focused .cell-inner-container:before { border-top: 1px solid transparent; } +/* left border */ +.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-left:before { + border-left: 1px solid transparent; +} + /* bottom border */ .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-bottom:before, .monaco-workbench .notebookOverlay .monaco-list .markdown-cell-row.focused .cell-inner-container:after { border-bottom: 1px solid transparent; } +/* right border */ +.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-right:before { + border-right: 1px solid transparent; +} + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-top:before, .monaco-workbench .notebookOverlay .monaco-list .markdown-cell-row.focused .cell-inner-container:before { top: 0; } + +.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-left:before { + left: 0; +} + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-bottom:before, .monaco-workbench .notebookOverlay .monaco-list .markdown-cell-row.focused .cell-inner-container:after { bottom: 0px; } +.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-right:before { + right: 0; +} + .monaco-workbench.hc-black .notebookOverlay .monaco-list-row .cell-editor-focus .cell-editor-part:before { outline-style: dashed; } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 497a6b80843..ddb4a83104b 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -681,6 +681,7 @@ export interface BaseCellRenderTemplate { deleteToolbar: ToolBar; betweenCellToolbar: ToolBar; focusIndicatorLeft: HTMLElement; + focusIndicatorRight: HTMLElement; disposables: DisposableStore; elementDisposables: DisposableStore; bottomCellContainer: HTMLElement; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 150a340969f..9e6520baba9 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -2403,7 +2403,10 @@ registerThemingParticipant((theme, collector) => { collector.addRule(` .monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-focus-indicator-top:before, .monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-focus-indicator-bottom:before, - .monaco-workbench .notebookOverlay .monaco-list:focus-within .markdown-cell-row.focused .cell-inner-container:not(.cell-editor-focus):before { + .monaco-workbench .notebookOverlay .monaco-list:focus-within .markdown-cell-row.focused .cell-inner-container:not(.cell-editor-focus):before, + .monaco-workbench .notebookOverlay .monaco-list:focus-within .markdown-cell-row.focused .cell-inner-container:not(.cell-editor-focus):after, + .monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-inner-container:not(.cell-editor-focus) .cell-focus-indicator-left:before, + .monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-inner-container:not(.cell-editor-focus) .cell-focus-indicator-right:before { border-color: ${focusedCellBorderColor} !important; }`); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts index 2bdc13a43b9..d9e413e8b26 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -266,8 +266,8 @@ abstract class AbstractCellRenderer { if (actions.primary.length || actions.secondary.length) { templateData.container.classList.add('cell-has-toolbar-actions'); if (isCodeCellRenderTemplate(templateData)) { - templateData.focusIndicatorLeft.style.top = `${EDITOR_TOOLBAR_HEIGHT + CELL_TOP_MARGIN}px`; - templateData.focusIndicatorRight.style.top = `${EDITOR_TOOLBAR_HEIGHT + CELL_TOP_MARGIN}px`; + templateData.focusIndicatorLeft.style.top = `${EDITOR_TOOLBAR_HEIGHT}px`; + templateData.focusIndicatorRight.style.top = `${EDITOR_TOOLBAR_HEIGHT}px`; } } else { templateData.container.classList.remove('cell-has-toolbar-actions'); @@ -401,6 +401,7 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR deleteToolbar.setActions([this.instantiationService.createInstance(DeleteCellAction)]); const focusIndicatorLeft = DOM.append(container, DOM.$('.cell-focus-indicator.cell-focus-indicator-side.cell-focus-indicator-left')); + const focusIndicatorRight = DOM.append(container, DOM.$('.cell-focus-indicator.cell-focus-indicator-side.cell-focus-indicator-right')); const codeInnerContent = DOM.append(container, $('.cell.code')); const editorPart = DOM.append(codeInnerContent, $('.cell-editor-part')); @@ -434,6 +435,7 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR editorContainer, focusIndicatorLeft, focusIndicatorBottom, + focusIndicatorRight, foldingIndicator, disposables, elementDisposables: new DisposableStore(), diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts index bda35e8bd33..d3fbea6a477 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts @@ -131,7 +131,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod } const statusbarHeight = this.getEditorStatusbarHeight(); - const indicatorHeight = editorHeight + statusbarHeight + outputTotalHeight + outputShowMoreContainerHeight; + const indicatorHeight = editorHeight + statusbarHeight + outputTotalHeight + outputShowMoreContainerHeight + (CELL_TOP_MARGIN * 2); const outputContainerOffset = EDITOR_TOOLBAR_HEIGHT + CELL_TOP_MARGIN + editorHeight + statusbarHeight; const outputShowMoreContainerOffset = totalHeight - BOTTOM_CELL_TOOLBAR_GAP - BOTTOM_CELL_TOOLBAR_HEIGHT / 2 - outputShowMoreContainerHeight; const bottomToolbarOffset = totalHeight - BOTTOM_CELL_TOOLBAR_GAP - BOTTOM_CELL_TOOLBAR_HEIGHT / 2; From 16df123b5aec640363083ef7dba50326c88713ad Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 11 Feb 2021 07:46:40 +0100 Subject: [PATCH 010/325] do not turn off settings sync when quality changed --- .../common/userDataAutoSyncService.ts | 33 +++++++++++++++++-- .../userDataAutoSyncService.ts | 4 ++- .../userDataSync/browser/userDataSync.ts | 7 ++-- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts index 246b17bc8fc..876f55d0054 100644 --- a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts @@ -19,6 +19,7 @@ import { toLocalISOString } from 'vs/base/common/date'; import { URI } from 'vs/base/common/uri'; import { isEqual } from 'vs/base/common/resources'; import { isWeb } from 'vs/base/common/platform'; +import { IProductService } from 'vs/platform/product/common/productService'; type AutoSyncClassification = { sources: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; @@ -37,6 +38,7 @@ const enablementKey = 'sync.enable'; const disableMachineEventuallyKey = 'sync.disableMachineEventually'; const sessionIdKey = 'sync.sessionId'; const storeUrlKey = 'sync.storeUrl'; +const productQualityKey = 'sync.productQuality'; interface _IUserDataAutoSyncEnablementService extends IUserDataAutoSyncEnablementService { canToggleEnablement(): boolean; @@ -120,7 +122,20 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto } } + private previousProductQuality: string | undefined; + private get productQuality(): string | undefined { + return this.storageService.get(productQualityKey, StorageScope.GLOBAL); + } + private set productQuality(productQuality: string | undefined) { + if (productQuality) { + this.storageService.store(productQualityKey, productQuality, StorageScope.GLOBAL, StorageTarget.MACHINE); + } else { + this.storageService.remove(productQualityKey, StorageScope.GLOBAL); + } + } + constructor( + @IProductService productService: IProductService, @IUserDataSyncStoreManagementService private readonly userDataSyncStoreManagementService: IUserDataSyncStoreManagementService, @IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService, @IUserDataSyncResourceEnablementService private readonly userDataSyncResourceEnablementService: IUserDataSyncResourceEnablementService, @@ -139,6 +154,9 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto this.lastSyncUrl = this.syncUrl; this.syncUrl = userDataSyncStoreManagementService.userDataSyncStore?.url; + this.previousProductQuality = this.productQuality; + this.productQuality = productService.quality; + if (this.syncUrl) { this.logService.info('Using settings sync service', this.syncUrl.toString()); @@ -258,6 +276,10 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto } } + private hasProductQualityChanged(): boolean { + return !!this.previousProductQuality && !!this.productQuality && this.previousProductQuality !== this.productQuality; + } + private async onDidFinishSync(error: Error | undefined): Promise { if (!error) { // Sync finished without errors @@ -315,14 +337,21 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto // Service changed else if (userDataSyncError.code === UserDataSyncErrorCode.ServiceChanged || userDataSyncError.code === UserDataSyncErrorCode.DefaultServiceChanged) { - if (userDataSyncError.code === UserDataSyncErrorCode.DefaultServiceChanged && isWeb) { + + // Check if default settings sync service has changed in web without changing the product quality + // Then turn off settings sync and ask user to turn on again + if (isWeb && userDataSyncError.code === UserDataSyncErrorCode.DefaultServiceChanged && !this.hasProductQualityChanged()) { await this.turnOff(false, true /* force soft turnoff on error */); this.logService.info('Auto Sync: Turned off sync because default sync service is changed.'); - } else { + } + + // Service has changed by the user. So turn off and turn on sync silently + else { await this.turnOff(false, true /* force soft turnoff on error */, true /* do not disable machine */); await this.turnOn(); this.logService.info('Auto Sync: Sync Service changed. Turned off auto sync, reset local state and turned on auto sync.'); } + } else { diff --git a/src/vs/platform/userDataSync/electron-sandbox/userDataAutoSyncService.ts b/src/vs/platform/userDataSync/electron-sandbox/userDataAutoSyncService.ts index 115f5ff011f..b2757dcd7b7 100644 --- a/src/vs/platform/userDataSync/electron-sandbox/userDataAutoSyncService.ts +++ b/src/vs/platform/userDataSync/electron-sandbox/userDataAutoSyncService.ts @@ -11,10 +11,12 @@ import { IUserDataSyncAccountService } from 'vs/platform/userDataSync/common/use import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IUserDataSyncMachinesService } from 'vs/platform/userDataSync/common/userDataSyncMachines'; +import { IProductService } from 'vs/platform/product/common/productService'; export class UserDataAutoSyncService extends BaseUserDataAutoSyncService { constructor( + @IProductService productService: IProductService, @IUserDataSyncStoreManagementService userDataSyncStoreManagementService: IUserDataSyncStoreManagementService, @IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService, @IUserDataSyncResourceEnablementService userDataSyncResourceEnablementService: IUserDataSyncResourceEnablementService, @@ -27,7 +29,7 @@ export class UserDataAutoSyncService extends BaseUserDataAutoSyncService { @IStorageService storageService: IStorageService, @IUserDataAutoSyncEnablementService userDataAutoSyncEnablementService: IUserDataAutoSyncEnablementService, ) { - super(userDataSyncStoreManagementService, userDataSyncStoreService, userDataSyncResourceEnablementService, userDataSyncService, logService, authTokenService, telemetryService, userDataSyncMachinesService, storageService, userDataAutoSyncEnablementService); + super(productService, userDataSyncStoreManagementService, userDataSyncStoreService, userDataSyncResourceEnablementService, userDataSyncService, logService, authTokenService, telemetryService, userDataSyncMachinesService, storageService, userDataAutoSyncEnablementService); this._register(Event.debounce(Event.any( Event.map(nativeHostService.onDidFocusWindow, () => 'windowFocus'), diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 071d0f01ff8..4d0b65c016b 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -54,7 +54,6 @@ import { UserDataSyncDataViews } from 'vs/workbench/contrib/userDataSync/browser import { IUserDataSyncWorkbenchService, getSyncAreaLabel, AccountStatus, CONTEXT_SYNC_STATE, CONTEXT_SYNC_ENABLEMENT, CONTEXT_ACCOUNT_STATE, CONFIGURE_SYNC_COMMAND_ID, SHOW_SYNC_LOG_COMMAND_ID, SYNC_VIEW_CONTAINER_ID, SYNC_TITLE, SYNC_VIEW_ICON } from 'vs/workbench/services/userDataSync/common/userDataSync'; import { Codicon } from 'vs/base/common/codicons'; import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer'; -import { isWeb } from 'vs/base/common/platform'; const CONTEXT_CONFLICTS_SOURCES = new RawContextKey('conflictsSources', ''); @@ -325,10 +324,12 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo }); return; case UserDataSyncErrorCode.DefaultServiceChanged: - if (isEqual(this.userDataSyncStoreManagementService.userDataSyncStore?.url, this.userDataSyncStoreManagementService.userDataSyncStore?.insidersUrl) && isWeb) { + // Check if Settings Sync got turned off because default service has changed. + // Then ask user to turn on sync again. + if (!this.userDataAutoSyncEnablementService.isEnabled()) { this.notificationService.notify({ severity: Severity.Info, - message: localize('switched to insiders', "Settings sync was turned off because VSCode Insiders now uses a separate service. Please turn on sync again."), + message: localize('switched to insiders', "Settings sync was turned off because VSCode now uses a separate service. Please turn on sync again."), actions: { primary: [new Action('turn on sync', localize('turn on sync', "Turn on Settings Sync..."), undefined, true, () => this.turnOn())] } From 7d5d5f5e7f80619b7a6ea3a81b1dfbba1aa9633e Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 11 Feb 2021 09:33:14 +0100 Subject: [PATCH 011/325] wire up `supportedLanguages` from extension kernel --- src/vs/vscode.proposed.d.ts | 3 ++- src/vs/workbench/api/common/extHostNotebook.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index a33fa80aad2..e740e259f91 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1586,7 +1586,8 @@ declare module 'vscode' { // todo@API // languages supported by kernel // first is preferred - // languages: string[]; + // `undefined` means all languages available in the editor + supportedLanguages?: string[]; // @roblourens // todo@API change to `executeCells(document: NotebookDocument, cells: NotebookCellRange[], context:{isWholeNotebooke: boolean}, token: CancelationToken): void;` diff --git a/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts index 3ca6106e7e7..7e80e14cd36 100644 --- a/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -126,7 +126,8 @@ export class ExtHostNotebookKernelProviderAdapter extends Disposable { description: kernel.description, detail: kernel.detail, isPreferred: kernel.isPreferred, - preloads: kernel.preloads + preloads: kernel.preloads, + supportedLanguages: kernel.supportedLanguages }; }); From 6f1cfdbae8ad4d1df0e1d7d4e127b66503b6e62e Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 11 Feb 2021 09:33:56 +0100 Subject: [PATCH 012/325] :lipstick: jsdoc --- src/vs/vscode.proposed.d.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index e740e259f91..ebd39ee0a42 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1583,10 +1583,11 @@ declare module 'vscode' { isPreferred?: boolean; preloads?: Uri[]; - // todo@API - // languages supported by kernel - // first is preferred - // `undefined` means all languages available in the editor + /** + * languages supported by kernel + * - first is preferred + * - `undefined` means all languages available in the editor + */ supportedLanguages?: string[]; // @roblourens From 55d267293b9a94b1ac8860b9dc59bc7163d2dfc3 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 11 Feb 2021 09:59:11 +0100 Subject: [PATCH 013/325] have a clear separation between KernelProvider and Kernel --- .../api/browser/mainThreadNotebook.ts | 79 ++++++++++++------- .../notebook/browser/contrib/coreActions.ts | 2 +- .../notebook/browser/notebookEditorWidget.ts | 2 +- .../notebook/browser/notebookServiceImpl.ts | 29 +------ .../contrib/notebook/common/notebookCommon.ts | 5 +- .../notebook/common/notebookService.ts | 2 +- 6 files changed, 58 insertions(+), 61 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts index 7e09d9d1bbf..a4c42e98713 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -23,7 +23,7 @@ import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookB import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService'; -import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, DisplayOrderKey, ICellEditOperation, ICellRange, IEditor, IMainCellDto, INotebookDecorationRenderOptions, INotebookDocumentFilter, INotebookEditorModel, INotebookExclusiveDocumentFilter, NotebookCellsChangeType, NOTEBOOK_DISPLAY_ORDER, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, DisplayOrderKey, ICellEditOperation, ICellRange, IEditor, IMainCellDto, INotebookDecorationRenderOptions, INotebookDocumentFilter, INotebookEditorModel, INotebookExclusiveDocumentFilter, INotebookKernelInfo2, NotebookCellsChangeType, NOTEBOOK_DISPLAY_ORDER, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService'; import { IMainNotebookController, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IEditorGroup, IEditorGroupsService, preferredSideBySideGroupDirection } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -140,6 +140,21 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo this.registerListeners(); } + dispose(): void { + super.dispose(); + + // remove all notebook providers + for (let item of this._notebookProviders.values()) { + item.disposable.dispose(); + } + + // remove all kernel providers + for (let item of this._notebookKernelProviders.values()) { + item.emitter.dispose(); + item.provider.dispose(); + } + } + async $tryApplyEdits(_viewType: string, resource: UriComponents, modelVersionId: number, cellEdits: ICellEditOperation[]): Promise { const textModel = this._notebookService.getNotebookTextModel(URI.from(resource)); if (!textModel) { @@ -512,38 +527,48 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo async $registerNotebookKernelProvider(extension: NotebookExtensionDescription, handle: number, documentFilter: INotebookDocumentFilter): Promise { const emitter = new Emitter(); const that = this; + const provider = this._notebookService.registerNotebookKernelProvider({ providerExtensionId: extension.id.value, providerDescription: extension.description, onDidChangeKernels: emitter.event, selector: documentFilter, - provideKernels: async (uri: URI, token: CancellationToken) => { - const kernels = await that._proxy.$provideNotebookKernels(handle, uri, token); - return kernels.map(kernel => { - return { - ...kernel, - providerHandle: handle - }; - }); - }, - resolveKernel: (editorId: string, uri: URI, kernelId: string, token: CancellationToken) => { - return that._proxy.$resolveNotebookKernel(handle, editorId, uri, kernelId, token); - }, - executeNotebook: (uri: URI, kernelId: string, cellHandle: number | undefined) => { - this.logService.debug('MainthreadNotebooks.registerNotebookKernelProvider#executeNotebook', uri.path, kernelId, cellHandle); - return that._proxy.$executeNotebookKernelFromProvider(handle, uri, kernelId, cellHandle); - }, - cancelNotebook: (uri: URI, kernelId: string, cellHandle: number | undefined) => { - this.logService.debug('MainthreadNotebooks.registerNotebookKernelProvider#cancelNotebook', uri.path, kernelId, cellHandle); - return that._proxy.$cancelNotebookKernelFromProvider(handle, uri, kernelId, cellHandle); - }, - }); - this._notebookKernelProviders.set(handle, { - extension, - emitter, - provider - }); + provideKernels: async (uri: URI, token: CancellationToken): Promise => { + const result: INotebookKernelInfo2[] = []; + const kernelsDto = await that._proxy.$provideNotebookKernels(handle, uri, token); + for (const dto of kernelsDto) { + result.push({ + id: dto.id, + friendlyId: dto.friendlyId, + label: dto.label, + extension: dto.extension, + extensionLocation: dto.extensionLocation, + providerHandle: dto.providerHandle, + description: dto.description, + detail: dto.detail, + isPreferred: dto.isPreferred, + preloads: dto.preloads, + supportedLanguages: dto.supportedLanguages, + + resolve: (uri: URI, editorId: string, token: CancellationToken): Promise => { + this.logService.debug('MainthreadNotebooks.resolveNotebookKernel', uri.path, dto.friendlyId); + return this._proxy.$resolveNotebookKernel(handle, editorId, uri, dto.friendlyId, token); + }, + executeNotebookCell: (uri: URI, cellHandle: number | undefined): Promise => { + this.logService.debug('MainthreadNotebooks.executeNotebookCell', uri.path, dto.friendlyId, cellHandle); + return this._proxy.$executeNotebookKernelFromProvider(handle, uri, dto.friendlyId, cellHandle); + }, + cancelNotebookCell: (uri: URI, cellHandle: number | undefined): Promise => { + this.logService.debug('MainthreadNotebooks.cancelNotebookCell', uri.path, dto.friendlyId, cellHandle); + return this._proxy.$cancelNotebookKernelFromProvider(handle, uri, dto.friendlyId, cellHandle); + } + }); + } + return result; + } + }); + this._notebookKernelProviders.set(handle, { extension, emitter, provider }); return; } diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts index 304e86c73c6..51c176f58ea 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts @@ -2108,7 +2108,7 @@ CommandsRegistry.registerCommand('_resolveNotebookKernels', async (accessor, arg const notebookService = accessor.get(INotebookService); const uri = URI.revive(args.uri as UriComponents); const source = new CancellationTokenSource(); - const kernels = await notebookService.getContributedNotebookKernels(args.viewType, uri, source.token); + const kernels = await notebookService.getNotebookKernels(args.viewType, uri, source.token); source.dispose(); return kernels.map(provider => ({ diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 628eecf0cdb..873cbaeb52b 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -774,7 +774,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor } this._contributedKernelsComputePromise = createCancelablePromise(token => { - return this.notebookService.getContributedNotebookKernels(this.viewModel!.viewType, this.viewModel!.uri, token); + return this.notebookService.getNotebookKernels(this.viewModel!.viewType, this.viewModel!.uri, token); }); const result = await this._contributedKernelsComputePromise; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts index 6da32d01e45..88dbe304dbe 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts @@ -695,39 +695,14 @@ export class NotebookService extends Disposable implements INotebookService, ICu }); } - async getContributedNotebookKernels(viewType: string, resource: URI, token: CancellationToken): Promise { + async getNotebookKernels(viewType: string, resource: URI, token: CancellationToken): Promise { const filteredProvider = this.notebookKernelProviderInfoStore.get(viewType, resource); const result = new Array(filteredProvider.length); - const promises = filteredProvider.map(async (provider, index) => { const data = await provider.provideKernels(resource, token); - result[index] = data.map(dto => { - return { - id: dto.id, - extension: dto.extension, - extensionLocation: URI.revive(dto.extensionLocation), - friendlyId: dto.friendlyId, - label: dto.label, - description: dto.description, - detail: dto.detail, - isPreferred: dto.isPreferred, - preloads: dto.preloads, - providerHandle: dto.providerHandle, - resolve: async (uri: URI, editorId: string, token: CancellationToken) => { - return provider.resolveKernel(editorId, uri, dto.friendlyId, token); - }, - executeNotebookCell: async (uri: URI, handle: number | undefined) => { - return provider.executeNotebook(uri, dto.friendlyId, handle); - }, - cancelNotebookCell: (uri: URI, handle: number | undefined): Promise => { - return provider.cancelNotebook(uri, dto.friendlyId, handle); - } - }; - }); + result[index] = data; }); - await Promise.all(promises); - return flatten(result); } diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index 0b31351c1fc..30bdd50e4de 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -738,10 +738,7 @@ export interface INotebookKernelProvider { providerDescription?: string; selector: INotebookDocumentFilter; onDidChangeKernels: Event; - provideKernels(uri: URI, token: CancellationToken): Promise; - resolveKernel(editorId: string, uri: UriComponents, kernelId: string, token: CancellationToken): Promise; - executeNotebook(uri: URI, kernelId: string, handle: number | undefined): Promise; - cancelNotebook(uri: URI, kernelId: string, handle: number | undefined): Promise; + provideKernels(uri: URI, token: CancellationToken): Promise; } export class CellSequence implements ISequence { diff --git a/src/vs/workbench/contrib/notebook/common/notebookService.ts b/src/vs/workbench/contrib/notebook/common/notebookService.ts index b544d588609..4c44be93c05 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookService.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookService.ts @@ -52,7 +52,7 @@ export interface INotebookService { getMimeTypeInfo(textModel: NotebookTextModel, output: IOutputDto): readonly IOrderedMimeType[]; registerNotebookKernelProvider(provider: INotebookKernelProvider): IDisposable; - getContributedNotebookKernels(viewType: string, resource: URI, token: CancellationToken): Promise; + getNotebookKernels(viewType: string, resource: URI, token: CancellationToken): Promise; getContributedNotebookKernelProviders(): Promise; getContributedNotebookOutputRenderers(id: string): NotebookOutputRendererInfo | undefined; getRendererInfo(id: string): INotebookRendererInfo | undefined; From 471be7f8e60cc43fd9327404d0baed9636125eb0 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 11 Feb 2021 10:02:38 +0100 Subject: [PATCH 014/325] use web overrides while reading --- .../platform/userDataSync/common/userDataSyncStoreService.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts index 70dc4859d47..5c4e759cd66 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts @@ -56,7 +56,9 @@ export abstract class AbstractUserDataSyncStoreManagementService extends Disposa this._onDidChangeUserDataSyncStore.fire(); } - protected toUserDataSyncStore(productStore: ConfigurationSyncStore | undefined, configuredStore?: ConfigurationSyncStore): UserDataSyncStore | undefined { + protected toUserDataSyncStore(productStore: ConfigurationSyncStore & { web?: ConfigurationSyncStore } | undefined, configuredStore?: ConfigurationSyncStore): UserDataSyncStore | undefined { + // Check for web overrides for backward compatibility while reading previous store + productStore = isWeb && productStore?.web ? { ...productStore, ...productStore.web } : productStore; const value: Partial = { ...(productStore || {}), ...(configuredStore || {}) }; if (value && isString(value.url) From 9737b1aad1034fac8cbb65f4aff5bac355ce93d7 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 11 Feb 2021 11:58:03 +0100 Subject: [PATCH 015/325] move INotebookKernelInfoDto2 to protocol, separate kernel from dto, renames --- .../workbench/api/browser/mainThreadNotebook.ts | 11 +++++------ src/vs/workbench/api/common/extHost.protocol.ts | 16 +++++++++++++++- src/vs/workbench/api/common/extHostNotebook.ts | 4 ++-- .../browser/contrib/status/editorStatus.ts | 4 ++-- .../contrib/notebook/browser/notebookBrowser.ts | 6 +++--- .../notebook/browser/notebookEditorWidget.ts | 12 ++++++------ .../notebook/browser/notebookServiceImpl.ts | 6 +++--- .../contrib/notebook/common/notebookCommon.ts | 8 +++----- .../contrib/notebook/common/notebookService.ts | 7 ++----- .../contrib/notebook/test/testNotebookEditor.ts | 6 +++--- 10 files changed, 44 insertions(+), 36 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts index a4c42e98713..5284cbfc3ae 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -23,7 +23,7 @@ import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookB import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService'; -import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, DisplayOrderKey, ICellEditOperation, ICellRange, IEditor, IMainCellDto, INotebookDecorationRenderOptions, INotebookDocumentFilter, INotebookEditorModel, INotebookExclusiveDocumentFilter, INotebookKernelInfo2, NotebookCellsChangeType, NOTEBOOK_DISPLAY_ORDER, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, DisplayOrderKey, ICellEditOperation, ICellRange, IEditor, IMainCellDto, INotebookDecorationRenderOptions, INotebookDocumentFilter, INotebookEditorModel, INotebookExclusiveDocumentFilter, INotebookKernel, NotebookCellsChangeType, NOTEBOOK_DISPLAY_ORDER, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService'; import { IMainNotebookController, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IEditorGroup, IEditorGroupsService, preferredSideBySideGroupDirection } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -533,8 +533,8 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo providerDescription: extension.description, onDidChangeKernels: emitter.event, selector: documentFilter, - provideKernels: async (uri: URI, token: CancellationToken): Promise => { - const result: INotebookKernelInfo2[] = []; + provideKernels: async (uri: URI, token: CancellationToken): Promise => { + const result: INotebookKernel[] = []; const kernelsDto = await that._proxy.$provideNotebookKernels(handle, uri, token); for (const dto of kernelsDto) { @@ -543,14 +543,13 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo friendlyId: dto.friendlyId, label: dto.label, extension: dto.extension, - extensionLocation: dto.extensionLocation, + extensionLocation: URI.revive(dto.extensionLocation), providerHandle: dto.providerHandle, description: dto.description, detail: dto.detail, isPreferred: dto.isPreferred, - preloads: dto.preloads, + preloads: dto.preloads?.map(u => URI.revive(u)), supportedLanguages: dto.supportedLanguages, - resolve: (uri: URI, editorId: string, token: CancellationToken): Promise => { this.logService.debug('MainthreadNotebooks.resolveNotebookKernel', uri.path, dto.friendlyId); return this._proxy.$resolveNotebookKernel(handle, editorId, uri, dto.friendlyId, token); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index d3d2e2a7d8b..977793e43b2 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -51,7 +51,7 @@ import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService'; import { TunnelCreationOptions, TunnelProviderFeatures, TunnelOptions } from 'vs/platform/remote/common/tunnel'; import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline'; import { revive } from 'vs/base/common/marshalling'; -import { INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEventDto, NotebookDataDto, IMainCellDto, INotebookDocumentFilter, INotebookKernelInfoDto2, TransientMetadata, INotebookCellStatusBarEntry, ICellRange, INotebookDecorationRenderOptions, INotebookExclusiveDocumentFilter, IOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEventDto, NotebookDataDto, IMainCellDto, INotebookDocumentFilter, TransientMetadata, INotebookCellStatusBarEntry, ICellRange, INotebookDecorationRenderOptions, INotebookExclusiveDocumentFilter, IOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'; import { Dto } from 'vs/base/common/types'; import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable'; @@ -1777,6 +1777,20 @@ export interface INotebookDocumentsAndEditorsDelta { visibleEditors?: string[]; } +export interface INotebookKernelInfoDto2 { + id?: string; + friendlyId: string; + label: string; + extension: ExtensionIdentifier; + extensionLocation: UriComponents; + providerHandle?: number; + description?: string; + detail?: string; + isPreferred?: boolean; + preloads?: UriComponents[]; + supportedLanguages?: string[] +} + export interface ExtHostNotebookShape { $resolveNotebookData(viewType: string, uri: UriComponents, backupId?: string): Promise; $resolveNotebookEditor(viewType: string, uri: UriComponents, editorId: string): Promise; diff --git a/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts index 7e80e14cd36..cdabfbf95f3 100644 --- a/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -9,7 +9,7 @@ import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { URI, UriComponents } from 'vs/base/common/uri'; import * as UUID from 'vs/base/common/uuid'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { ExtHostNotebookShape, ICommandDto, IMainContext, IModelAddedData, INotebookDocumentPropertiesChangeData, INotebookDocumentsAndEditorsDelta, INotebookDocumentShowOptions, INotebookEditorPropertiesChangeData, MainContext, MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol'; +import { ExtHostNotebookShape, ICommandDto, IMainContext, IModelAddedData, INotebookDocumentPropertiesChangeData, INotebookDocumentsAndEditorsDelta, INotebookDocumentShowOptions, INotebookEditorPropertiesChangeData, INotebookKernelInfoDto2, MainContext, MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol'; import { ILogService } from 'vs/platform/log/common/log'; import { CommandsConverter, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; @@ -17,7 +17,7 @@ import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePa import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters'; import * as extHostTypes from 'vs/workbench/api/common/extHostTypes'; import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/webview'; -import { CellStatusbarAlignment, CellUri, INotebookCellStatusBarEntry, INotebookDisplayOrder, INotebookExclusiveDocumentFilter, INotebookKernelInfoDto2, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookDataDto, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellStatusbarAlignment, CellUri, INotebookCellStatusBarEntry, INotebookDisplayOrder, INotebookExclusiveDocumentFilter, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookDataDto, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import * as vscode from 'vscode'; import { ResourceMap } from 'vs/base/common/map'; import { ExtHostCell, ExtHostNotebookDocument } from './extHostNotebookDocument'; diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/status/editorStatus.ts b/src/vs/workbench/contrib/notebook/browser/contrib/status/editorStatus.ts index 2858f29bf52..5b3ec908aef 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/status/editorStatus.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/status/editorStatus.ts @@ -14,7 +14,7 @@ import { INotebookEditor, NOTEBOOK_IS_ACTIVE_EDITOR } from 'vs/workbench/contrib import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; -import { INotebookKernelInfo2 } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookKernel } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry, IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { Disposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; @@ -213,7 +213,7 @@ export class KernelStatus extends Disposable implements IWorkbenchContribution { } } - showKernelStatus(kernel: INotebookKernelInfo2 | undefined) { + showKernelStatus(kernel: INotebookKernel | undefined) { this.kernelInfoElement.value = this._statusbarService.addEntry({ text: kernel ? kernel.label : 'Choose Kernel', ariaLabel: kernel ? kernel.label : 'Choose Kernel', diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 4a19272e632..23f72d4fc5a 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -22,7 +22,7 @@ import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/outpu import { RunStateRenderer, TimerRenderer } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer'; import { CellViewModel, IModelDecorationsChangeAccessor, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; -import { CellKind, NotebookCellMetadata, NotebookDocumentMetadata, IEditor, INotebookKernelInfo2, ICellRange, IOrderedMimeType, INotebookRendererInfo, ICellOutput, IOutputItemDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, NotebookCellMetadata, NotebookDocumentMetadata, IEditor, INotebookKernel, ICellRange, IOrderedMimeType, INotebookRendererInfo, ICellOutput, IOutputItemDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { Webview } from 'vs/workbench/contrib/webview/browser/webview'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { IMenu } from 'vs/platform/actions/common/actions'; @@ -333,7 +333,7 @@ export interface INotebookEditor extends IEditor, ICommonNotebookEditor { readonly onDidChangeModel: Event; readonly onDidFocusEditorWidget: Event; readonly isNotebookEditor: boolean; - activeKernel: INotebookKernelInfo2 | undefined; + activeKernel: INotebookKernel | undefined; multipleKernelsAvailable: boolean; readonly onDidChangeAvailableKernels: Event; readonly onDidChangeKernel: Event; @@ -379,7 +379,7 @@ export interface INotebookEditor extends IEditor, ICommonNotebookEditor { /** * Fetch the contributed kernels for this notebook */ - beginComputeContributedKernels(): Promise; + beginComputeContributedKernels(): Promise; /** * Insert a new cell around `cell` diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 873cbaeb52b..dfc7eab903a 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -54,7 +54,7 @@ import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewMod import { NotebookEventDispatcher, NotebookLayoutChangedEvent } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; import { CellViewModel, IModelDecorationsChangeAccessor, INotebookEditorViewState, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; -import { CellKind, CellToolbarLocKey, ICellRange, INotebookDecorationRenderOptions, INotebookKernelInfo2, NotebookCellRunState, NotebookRunState, ShowCellStatusBarKey } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, CellToolbarLocKey, ICellRange, INotebookDecorationRenderOptions, INotebookKernel, NotebookCellRunState, NotebookRunState, ShowCellStatusBarKey } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { editorGutterModifiedBackground } from 'vs/workbench/contrib/scm/browser/dirtydiffDecorator'; @@ -149,20 +149,20 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor } private _activeKernelExecuted: boolean = false; - private _activeKernel: INotebookKernelInfo2 | undefined = undefined; + private _activeKernel: INotebookKernel | undefined = undefined; private readonly _onDidChangeKernel = this._register(new Emitter()); readonly onDidChangeKernel: Event = this._onDidChangeKernel.event; private readonly _onDidChangeAvailableKernels = this._register(new Emitter()); readonly onDidChangeAvailableKernels: Event = this._onDidChangeAvailableKernels.event; - private _contributedKernelsComputePromise: CancelablePromise | null = null; + private _contributedKernelsComputePromise: CancelablePromise | null = null; private _initialKernelComputationDone: boolean = false; get activeKernel() { return this._activeKernel; } - set activeKernel(kernel: INotebookKernelInfo2 | undefined) { + set activeKernel(kernel: INotebookKernel | undefined) { if (this._isDisposed) { return; } @@ -829,7 +829,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor tokenSource.dispose(); } - private async _setKernelsFromProviders(provider: NotebookProviderInfo, kernels: INotebookKernelInfo2[], tokenSource: CancellationTokenSource) { + private async _setKernelsFromProviders(provider: NotebookProviderInfo, kernels: INotebookKernel[], tokenSource: CancellationTokenSource) { const rawAssociations = this.configurationService.getValue(notebookKernelProviderAssociationsSettingId) || []; const userSetKernelProvider = rawAssociations.filter(e => e.viewType === this.viewModel?.viewType)[0]?.kernelProvider; const memento = this._activeKernelMemento.getMemento(StorageScope.GLOBAL, StorageTarget.MACHINE); @@ -915,7 +915,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor tokenSource.dispose(); } - private async _loadKernelPreloads(extensionLocation: URI, kernel: INotebookKernelInfo2) { + private async _loadKernelPreloads(extensionLocation: URI, kernel: INotebookKernel) { if (kernel.preloads && kernel.preloads.length) { await this._resolveWebview(); this._webview?.updateKernelPreloads([extensionLocation], kernel.preloads.map(preload => URI.revive(preload))); diff --git a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts index 88dbe304dbe..e3019fbe075 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts @@ -32,7 +32,7 @@ import { NotebookKernelProviderAssociationRegistry, NotebookViewTypesExtensionRe import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; -import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, BUILTIN_RENDERER_ID, CellEditType, CellKind, DisplayOrderKey, ICellEditOperation, INotebookDecorationRenderOptions, INotebookKernelInfo2, INotebookKernelProvider, INotebookRendererInfo, INotebookTextModel, IOrderedMimeType, IOutputDto, mimeTypeIsAlwaysSecure, mimeTypeSupportedByCore, notebookDocumentFilterMatch, NotebookEditorPriority, NOTEBOOK_DISPLAY_ORDER, RENDERER_NOT_AVAILABLE, sortMimeTypes } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, BUILTIN_RENDERER_ID, CellEditType, CellKind, DisplayOrderKey, ICellEditOperation, INotebookDecorationRenderOptions, INotebookKernel, INotebookKernelProvider, INotebookRendererInfo, INotebookTextModel, IOrderedMimeType, IOutputDto, mimeTypeIsAlwaysSecure, mimeTypeSupportedByCore, notebookDocumentFilterMatch, NotebookEditorPriority, NOTEBOOK_DISPLAY_ORDER, RENDERER_NOT_AVAILABLE, sortMimeTypes } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookOutputRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookOutputRenderer'; import { NotebookEditorDescriptor, NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider'; import { IMainNotebookController, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; @@ -695,9 +695,9 @@ export class NotebookService extends Disposable implements INotebookService, ICu }); } - async getNotebookKernels(viewType: string, resource: URI, token: CancellationToken): Promise { + async getNotebookKernels(viewType: string, resource: URI, token: CancellationToken): Promise { const filteredProvider = this.notebookKernelProviderInfoStore.get(viewType, resource); - const result = new Array(filteredProvider.length); + const result = new Array(filteredProvider.length); const promises = filteredProvider.map(async (provider, index) => { const data = await provider.provideKernels(resource, token); result[index] = data; diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index 30bdd50e4de..e758dcb76c9 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -713,7 +713,7 @@ export function notebookDocumentFilterMatch(filter: INotebookDocumentFilter, vie return false; } -export interface INotebookKernelInfoDto2 { +export interface INotebookKernel { id?: string; friendlyId: string; label: string; @@ -723,11 +723,9 @@ export interface INotebookKernelInfoDto2 { description?: string; detail?: string; isPreferred?: boolean; - preloads?: UriComponents[]; + preloads?: URI[]; supportedLanguages?: string[] -} -export interface INotebookKernelInfo2 extends INotebookKernelInfoDto2 { resolve(uri: URI, editorId: string, token: CancellationToken): Promise; executeNotebookCell(uri: URI, handle: number | undefined): Promise; cancelNotebookCell(uri: URI, handle: number | undefined): Promise; @@ -738,7 +736,7 @@ export interface INotebookKernelProvider { providerDescription?: string; selector: INotebookDocumentFilter; onDidChangeKernels: Event; - provideKernels(uri: URI, token: CancellationToken): Promise; + provideKernels(uri: URI, token: CancellationToken): Promise; } export class CellSequence implements ISequence { diff --git a/src/vs/workbench/contrib/notebook/common/notebookService.ts b/src/vs/workbench/contrib/notebook/common/notebookService.ts index 4c44be93c05..7aa033d221e 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookService.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookService.ts @@ -8,10 +8,7 @@ import { URI } from 'vs/base/common/uri'; import { NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider'; import { NotebookExtensionDescription } from 'vs/workbench/api/common/extHost.protocol'; import { Event } from 'vs/base/common/event'; -import { - INotebookTextModel, INotebookRendererInfo, - IEditor, INotebookKernelProvider, INotebookKernelInfo2, TransientMetadata, NotebookDataDto, TransientOptions, INotebookDecorationRenderOptions, INotebookExclusiveDocumentFilter, IOrderedMimeType, IOutputDto -} from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookTextModel, INotebookRendererInfo, IEditor, INotebookKernelProvider, INotebookKernel, TransientMetadata, NotebookDataDto, TransientOptions, INotebookDecorationRenderOptions, INotebookExclusiveDocumentFilter, IOrderedMimeType, IOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { CancellationToken } from 'vs/base/common/cancellation'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; @@ -52,7 +49,7 @@ export interface INotebookService { getMimeTypeInfo(textModel: NotebookTextModel, output: IOutputDto): readonly IOrderedMimeType[]; registerNotebookKernelProvider(provider: INotebookKernelProvider): IDisposable; - getNotebookKernels(viewType: string, resource: URI, token: CancellationToken): Promise; + getNotebookKernels(viewType: string, resource: URI, token: CancellationToken): Promise; getContributedNotebookKernelProviders(): Promise; getContributedNotebookOutputRenderers(id: string): NotebookOutputRendererInfo | undefined; getRendererInfo(id: string): INotebookRendererInfo | undefined; diff --git a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts index b97ea772c15..b49ef38f8b2 100644 --- a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts @@ -18,7 +18,7 @@ import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/v import { CellViewModel, IModelDecorationsChangeAccessor, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; -import { CellKind, CellUri, INotebookEditorModel, NotebookCellMetadata, ICellRange, INotebookKernelInfo2, notebookDocumentMetadataDefaults, IOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, CellUri, INotebookEditorModel, NotebookCellMetadata, ICellRange, INotebookKernel, notebookDocumentMetadataDefaults, IOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { Webview } from 'vs/workbench/contrib/webview/browser/webview'; import { ICompositeCodeEditor, IEditor } from 'vs/editor/common/editorCommon'; import { NotImplementedError } from 'vs/base/common/errors'; @@ -87,7 +87,7 @@ export class TestNotebookEditor implements INotebookEditor { updateOutputHeight(cellInfo: ICommonCellInfo, output: ICellOutputViewModel, height: number, isInit: boolean): void { throw new Error('Method not implemented.'); } - async beginComputeContributedKernels(): Promise { + async beginComputeContributedKernels(): Promise { return []; } setEditorDecorations(key: string, range: ICellRange): void { @@ -142,7 +142,7 @@ export class TestNotebookEditor implements INotebookEditor { } cursorNavigationMode = false; - activeKernel: INotebookKernelInfo2 | undefined; + activeKernel: INotebookKernel | undefined; onDidChangeKernel: Event = new Emitter().event; onDidChangeActiveEditor: Event = new Emitter().event; activeCodeEditor: IEditor | undefined; From 474e769014cccc35a8389e93562addcacdf8ceb9 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 11 Feb 2021 12:38:28 +0100 Subject: [PATCH 016/325] stop using `resolvedLanguages`, only use kernel languages or all languages --- .../contrib/notebook/browser/contrib/coreActions.ts | 2 +- .../contrib/notebook/browser/notebookEditorWidget.ts | 6 ++++-- .../contrib/notebook/common/model/notebookTextModel.ts | 5 +++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts index 51c176f58ea..9705204ab05 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts @@ -1625,7 +1625,7 @@ export class ChangeCellLanguageAction extends NotebookCellAction { const quickInputService = accessor.get(IQuickInputService); const providerLanguages = [ - ...(context.notebookEditor.activeKernel?.supportedLanguages ?? context.notebookEditor.viewModel.notebookDocument.resolvedLanguages), + ...(context.notebookEditor.activeKernel?.supportedLanguages ?? modeService.getRegisteredModes()), 'markdown' ]; providerLanguages.forEach(languageId => { diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index dfc7eab903a..f7e5b0625ac 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -64,6 +64,7 @@ import { configureKernelIcon, errorStateIcon, successStateIcon } from 'vs/workbe import { debugIconStartForeground } from 'vs/workbench/contrib/debug/browser/debugColors'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { extname } from 'vs/base/common/resources'; +import { IModeService } from 'vs/editor/common/services/modeService'; const $ = DOM.$; @@ -256,7 +257,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor @IMenuService private readonly menuService: IMenuService, @IQuickInputService private readonly quickInputService: IQuickInputService, @IThemeService private readonly themeService: IThemeService, - @ITelemetryService private readonly telemetryService: ITelemetryService + @ITelemetryService private readonly telemetryService: ITelemetryService, + @IModeService private readonly modeService: IModeService, ) { super(); this.isEmbedded = creationOptions.isEmbedded || false; @@ -1470,7 +1472,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor const nextIndex = ui ? this.viewModel.getNextVisibleCellIndex(index) : index + 1; let language; if (type === CellKind.Code) { - const supportedLanguages = this._activeKernel?.supportedLanguages ?? this.viewModel.notebookDocument.resolvedLanguages; + const supportedLanguages = this._activeKernel?.supportedLanguages ?? this.modeService.getRegisteredModes(); const defaultLanguage = supportedLanguages[0] || 'plaintext'; if (cell?.cellKind === CellKind.Code) { language = cell.language; diff --git a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts index 38a90af56c6..a89ab1a0edb 100644 --- a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts +++ b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts @@ -220,7 +220,8 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel return this._languages; } - get resolvedLanguages() { + /** @deprecated */ + private get _resolvedLanguages() { if (this._allLanguages) { return this._modeService.getRegisteredModes(); } @@ -456,7 +457,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel this._allLanguages = allLanguages !== undefined; this._languages = languages; - const resolvedLanguages = this.resolvedLanguages; + const resolvedLanguages = this._resolvedLanguages; if (resolvedLanguages.length && this._cells.length) { this._cells[0].language = resolvedLanguages[0]; } From ccc28e3726a6d8e2266f9d8990961b22c6e7d6c4 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 11 Feb 2021 14:21:40 +0100 Subject: [PATCH 017/325] Remove languages property from NotebookData and NotebookDocument --- .../src/notebook.test.ts | 8 ++++- .../src/notebookSmokeTestMain.ts | 1 - .../src/notebookTestMain.ts | 7 ++-- src/vs/vscode.proposed.d.ts | 11 +----- .../api/browser/mainThreadNotebook.ts | 7 ---- .../workbench/api/common/extHost.protocol.ts | 1 - .../workbench/api/common/extHostNotebook.ts | 3 +- .../api/common/extHostNotebookDocument.ts | 11 +----- .../notebook/browser/notebookServiceImpl.ts | 4 +-- .../common/model/notebookTextModel.ts | 36 +------------------ .../contrib/notebook/common/notebookCommon.ts | 5 --- .../common/services/notebookSimpleWorker.ts | 4 +-- .../services/notebookWorkerServiceImpl.ts | 1 - .../notebook/test/notebookViewModel.test.ts | 10 +++--- .../notebook/test/testNotebookEditor.ts | 4 +-- 15 files changed, 22 insertions(+), 91 deletions(-) diff --git a/extensions/vscode-notebook-tests/src/notebook.test.ts b/extensions/vscode-notebook-tests/src/notebook.test.ts index ca66acd63b6..ad15fd0a3eb 100644 --- a/extensions/vscode-notebook-tests/src/notebook.test.ts +++ b/extensions/vscode-notebook-tests/src/notebook.test.ts @@ -1468,7 +1468,13 @@ suite('regression', () => { assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.document.getText(), 'var abc = 0;'); - assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.language, 'typescript'); + + // todo@jrieken enforce a kernel (how) and test that its language is picked + // assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.language, 'typescript'); + + // no kernel -> no default language + assert.strictEqual(vscode.window.activeNotebookEditor!.kernel, undefined); + assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.language, 'plaintext'); await vscode.commands.executeCommand('vscode.openWith', resource, 'default'); assert.strictEqual(vscode.window.activeTextEditor?.document.uri.path, resource.path); diff --git a/extensions/vscode-notebook-tests/src/notebookSmokeTestMain.ts b/extensions/vscode-notebook-tests/src/notebookSmokeTestMain.ts index 686397a0f87..78a201526fc 100644 --- a/extensions/vscode-notebook-tests/src/notebookSmokeTestMain.ts +++ b/extensions/vscode-notebook-tests/src/notebookSmokeTestMain.ts @@ -23,7 +23,6 @@ export function smokeTestActivate(context: vscode.ExtensionContext): any { context.subscriptions.push(vscode.notebook.registerNotebookContentProvider('notebookSmokeTest', { openNotebook: async (_resource: vscode.Uri) => { const dto: vscode.NotebookData = { - languages: ['typescript'], metadata: {}, cells: [ { diff --git a/extensions/vscode-notebook-tests/src/notebookTestMain.ts b/extensions/vscode-notebook-tests/src/notebookTestMain.ts index 32d25475aa9..ef3c477d6e5 100644 --- a/extensions/vscode-notebook-tests/src/notebookTestMain.ts +++ b/extensions/vscode-notebook-tests/src/notebookTestMain.ts @@ -10,17 +10,15 @@ export function activate(context: vscode.ExtensionContext): any { smokeTestActivate(context); context.subscriptions.push(vscode.notebook.registerNotebookContentProvider('notebookCoreTest', { - openNotebook: async (_resource: vscode.Uri) => { + openNotebook: async (_resource: vscode.Uri): Promise => { if (/.*empty\-.*\.vsctestnb$/.test(_resource.path)) { return { - languages: ['typescript'], metadata: {}, cells: [] }; } const dto: vscode.NotebookData = { - languages: ['typescript'], metadata: { custom: { testMetadata: false } }, @@ -36,7 +34,6 @@ export function activate(context: vscode.ExtensionContext): any { } ] }; - return dto; }, resolveNotebook: async (_document: vscode.NotebookDocument) => { @@ -60,6 +57,7 @@ export function activate(context: vscode.ExtensionContext): any { id: 'mainKernel', label: 'Notebook Test Kernel', isPreferred: true, + supportedLanguages: ['typescript'], executeAllCells: async (_document: vscode.NotebookDocument) => { const edit = new vscode.WorkspaceEdit(); @@ -98,6 +96,7 @@ export function activate(context: vscode.ExtensionContext): any { id: 'secondaryKernel', label: 'Notebook Secondary Test Kernel', isPreferred: false, + supportedLanguages: ['typescript'], executeAllCells: async (_document: vscode.NotebookDocument) => { const edit = new vscode.WorkspaceEdit(); edit.replaceNotebookCellOutput(_document.uri, 0, [new vscode.NotebookCellOutput([ diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index ebd39ee0a42..28068a8c2a3 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1080,11 +1080,6 @@ declare module 'vscode' { * When false, insecure outputs like HTML, JavaScript, SVG will not be rendered. */ trusted?: boolean; - - /** - * Languages the document supports - */ - languages?: string[]; } export interface NotebookDocumentContentOptions { @@ -1110,10 +1105,6 @@ declare module 'vscode' { readonly isUntitled: boolean; readonly cells: ReadonlyArray; readonly contentOptions: NotebookDocumentContentOptions; - // todo@API - // - move to kernel -> control runnable state of a cell - // - remove from this type - languages: string[]; readonly metadata: NotebookDocumentMetadata; } @@ -1258,7 +1249,6 @@ declare module 'vscode' { export interface NotebookData { readonly cells: NotebookCellData[]; - readonly languages: string[]; readonly metadata: NotebookDocumentMetadata; } @@ -1583,6 +1573,7 @@ declare module 'vscode' { isPreferred?: boolean; preloads?: Uri[]; + // TODO@API control runnable state of cell /** * languages supported by kernel * - first is preferred diff --git a/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts index 5284cbfc3ae..617f46a2a2c 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -460,7 +460,6 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo viewOptions: options.viewOptions, reloadNotebook: async (mainthreadTextModel: NotebookTextModel) => { const data = await this._proxy.$resolveNotebookData(viewType, mainthreadTextModel.uri); - mainthreadTextModel.updateLanguages(data.languages); mainthreadTextModel.metadata = data.metadata; mainthreadTextModel.transientOptions = contentOptions; @@ -587,12 +586,6 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo entry?.emitter.fire(uriComponents ? URI.revive(uriComponents) : undefined); } - async $updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise { - this.logService.debug('MainThreadNotebooks#updateNotebookLanguages', resource.path, languages); - const textModel = this._notebookService.getNotebookTextModel(URI.from(resource)); - textModel?.updateLanguages(languages); - } - async $postMessage(editorId: string, forRendererId: string | undefined, value: any): Promise { const editor = this._notebookService.getNotebookEditor(editorId) as INotebookEditor | undefined; if (editor?.isNotebookEditor) { diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 977793e43b2..732a3f000dd 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -789,7 +789,6 @@ export interface MainThreadNotebookShape extends IDisposable { $unregisterNotebookKernelProvider(handle: number): Promise; $onNotebookKernelChange(handle: number, uri: UriComponents | undefined): void; $tryApplyEdits(viewType: string, resource: UriComponents, modelVersionId: number, edits: ICellEditOperation[]): Promise; - $updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise; $postMessage(editorId: string, forRendererId: string | undefined, value: any): Promise; $setStatusBarEntry(id: number, statusBarEntry: INotebookCellStatusBarEntryDto): Promise; $tryOpenDocument(uriComponents: UriComponents, viewType?: string): Promise; diff --git a/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts index cdabfbf95f3..40ff93d7dd5 100644 --- a/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -454,7 +454,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN ...notebookDocumentMetadataDefaults, ...data.metadata }, - languages: data.languages, cells: data.cells.map(typeConverters.NotebookCellData.from), }; } @@ -707,7 +706,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN } const that = this; - const document = new ExtHostNotebookDocument(this._proxy, this._documentsAndEditors, { + const document = new ExtHostNotebookDocument(this._documentsAndEditors, { emitModelChange(event: vscode.NotebookCellsChangeEvent): void { that._onDidChangeNotebookCells.fire(event); }, diff --git a/src/vs/workbench/api/common/extHostNotebookDocument.ts b/src/vs/workbench/api/common/extHostNotebookDocument.ts index b20fb518865..053edfad772 100644 --- a/src/vs/workbench/api/common/extHostNotebookDocument.ts +++ b/src/vs/workbench/api/common/extHostNotebookDocument.ts @@ -10,7 +10,7 @@ import { Schemas } from 'vs/base/common/network'; import { joinPath } from 'vs/base/common/resources'; import { ISplice } from 'vs/base/common/sequence'; import { URI } from 'vs/base/common/uri'; -import { CellKind, INotebookDocumentPropertiesChangeData, MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol'; +import { CellKind, INotebookDocumentPropertiesChangeData } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostDocumentsAndEditors, IExtHostModelAddedData } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters'; import { IMainCellDto, IOutputDto, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon'; @@ -144,10 +144,8 @@ export class ExtHostNotebookDocument extends Disposable { private _backupCounter = 1; private _backup?: vscode.NotebookDocumentBackup; private _disposed = false; - private _languages: string[] = []; constructor( - private readonly _proxy: MainThreadNotebookShape, private readonly _documentsAndEditors: ExtHostDocumentsAndEditors, private readonly _emitter: INotebookEventEmitter, private readonly _viewType: string, @@ -177,8 +175,6 @@ export class ExtHostNotebookDocument extends Disposable { get isDirty() { return that._isDirty; }, get isUntitled() { return that.uri.scheme === Schemas.untitled; }, get cells(): ReadonlyArray { return that._cells.map(cell => cell.cell); }, - get languages() { return that._languages; }, - set languages(value: string[]) { that._trySetLanguages(value); }, get metadata() { return that._metadata; }, set metadata(_value: Required) { throw new Error('Use WorkspaceEdit to update metadata.'); }, get contentOptions() { return that._contentOptions; } @@ -187,11 +183,6 @@ export class ExtHostNotebookDocument extends Disposable { return this._notebook; } - private _trySetLanguages(newLanguages: string[]) { - this._languages = newLanguages; - this._proxy.$updateNotebookLanguages(this._viewType, this.uri, this._languages); - } - getNewBackupUri(): URI { if (!this._storagePath) { throw new Error('Backup requires a valid storage path'); diff --git a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts index e3019fbe075..f47d387b488 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts @@ -735,13 +735,13 @@ export class NotebookService extends Disposable implements INotebookService, ICu const dataDto = await provider.controller.resolveNotebookDocument(viewType, uri, backupId); let cells = dataDto.data.cells.length ? dataDto.data.cells : (uri.scheme === Schemas.untitled ? [{ cellKind: CellKind.Code, - language: dataDto.data.languages.length ? dataDto.data.languages[0] : '', + language: 'plaintext', //TODO@jrieken unsure what this is outputs: [], metadata: undefined, source: '' }] : []); - notebookModel = this._instantiationService.createInstance(NotebookTextModel, viewType, provider.controller.supportBackup, uri, cells, dataDto.data.languages, dataDto.data.metadata, dataDto.transientOptions); + notebookModel = this._instantiationService.createInstance(NotebookTextModel, viewType, provider.controller.supportBackup, uri, cells, dataDto.data.metadata, dataDto.transientOptions); } // new notebook model created diff --git a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts index a89ab1a0edb..3885b5e3d02 100644 --- a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts +++ b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts @@ -12,7 +12,6 @@ import { ITextSnapshot } from 'vs/editor/common/model'; import { IUndoRedoService, UndoRedoElementType, IUndoRedoElement, IResourceUndoRedoElement, UndoRedoGroup, IWorkspaceUndoRedoElement } from 'vs/platform/undoRedo/common/undoRedo'; import { MoveCellEdit, SpliceCellsEdit, CellMetadataEdit } from 'vs/workbench/contrib/notebook/common/model/cellEdit'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; -import { IModeService } from 'vs/editor/common/services/modeService'; import { ISequence, LcsDiff } from 'vs/base/common/diff/diff'; import { hash } from 'vs/base/common/hash'; import { NotebookCellOutputTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellOutputTextModel'; @@ -27,7 +26,7 @@ export class NotebookTextModelSnapshot implements ITextSnapshot { if (this._index === -1) { this._index++; - return `{ "metadata": ${JSON.stringify(this._model.metadata)}, "languages": ${JSON.stringify(this._model.languages)}, "cells": [`; + return `{ "metadata": ${JSON.stringify(this._model.metadata)}, "cells": [`; } if (this._index < this._model.cells.length) { @@ -213,21 +212,6 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel private _mapping: Map = new Map(); private _cellListeners: Map = new Map(); private _cells: NotebookCellTextModel[] = []; - private _languages: string[] = []; - private _allLanguages: boolean = false; - - get languages() { - return this._languages; - } - - /** @deprecated */ - private get _resolvedLanguages() { - if (this._allLanguages) { - return this._modeService.getRegisteredModes(); - } - - return this._languages; - } metadata: NotebookDocumentMetadata = notebookDocumentMetadataDefaults; transientOptions: TransientOptions = { transientMetadata: {}, transientOutputs: false }; @@ -248,17 +232,14 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel readonly supportBackup: boolean, readonly uri: URI, cells: ICellDto2[], - languages: string[], metadata: NotebookDocumentMetadata, options: TransientOptions, @IUndoRedoService private _undoService: IUndoRedoService, @ITextModelService private _modelService: ITextModelService, - @IModeService private readonly _modeService: IModeService, ) { super(); this.transientOptions = options; this.metadata = metadata; - this.updateLanguages(metadata.languages && metadata.languages.length ? metadata.languages : languages); this._initialize(cells); this._eventEmitter = new DelayedEmitter( @@ -452,17 +433,6 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel this._versionId = this._versionId + 1; } - updateLanguages(languages: string[]) { - const allLanguages = languages.find(lan => lan === '*'); - this._allLanguages = allLanguages !== undefined; - this._languages = languages; - - const resolvedLanguages = this._resolvedLanguages; - if (resolvedLanguages.length && this._cells.length) { - this._cells[0].language = resolvedLanguages[0]; - } - } - private _isDocumentMetadataChangeTransient(a: NotebookDocumentMetadata, b: NotebookDocumentMetadata) { const keys = new Set([...Object.keys(a || {}), ...Object.keys(b || {})]); for (let key of keys) { @@ -478,10 +448,6 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel const oldMetadata = this.metadata; this.metadata = metadata; - if (this.metadata.languages && this.metadata.languages.length) { - this.updateLanguages(this.metadata.languages); - } - if (computeUndoRedo) { const that = this; this._operationManager.pushEditOperation(new class implements IResourceUndoRedoElement { diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index e758dcb76c9..6971dd15aac 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -67,7 +67,6 @@ export const notebookDocumentMetadataDefaults: Required void): IDisposable; } @@ -375,7 +371,6 @@ export type ICellEditOperation = ICellReplaceEdit | ICellOutputEdit | ICellMetad export interface NotebookDataDto { readonly cells: ICellDto2[]; - readonly languages: string[]; readonly metadata: NotebookDocumentMetadata; } diff --git a/src/vs/workbench/contrib/notebook/common/services/notebookSimpleWorker.ts b/src/vs/workbench/contrib/notebook/common/services/notebookSimpleWorker.ts index 1e7ca334718..f81832d035a 100644 --- a/src/vs/workbench/contrib/notebook/common/services/notebookSimpleWorker.ts +++ b/src/vs/workbench/contrib/notebook/common/services/notebookSimpleWorker.ts @@ -88,7 +88,6 @@ class MirrorNotebookDocument { constructor( readonly uri: URI, public cells: MirrorCell[], - public languages: string[], public metadata: NotebookDocumentMetadata, ) { } @@ -175,7 +174,7 @@ export class NotebookEditorSimpleWorker implements IRequestHandler, IDisposable dto.cellKind, dto.outputs, dto.metadata - )), data.languages, data.metadata); + )), data.metadata); } public acceptModelChanged(strURL: string, event: NotebookCellsChangedEventDto) { @@ -266,4 +265,3 @@ export class NotebookEditorSimpleWorker implements IRequestHandler, IDisposable export function create(host: EditorWorkerHost): IRequestHandler { return new NotebookEditorSimpleWorker(); } - diff --git a/src/vs/workbench/contrib/notebook/common/services/notebookWorkerServiceImpl.ts b/src/vs/workbench/contrib/notebook/common/services/notebookWorkerServiceImpl.ts index 5d1f47606ec..395bf87c2ec 100644 --- a/src/vs/workbench/contrib/notebook/common/services/notebookWorkerServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/common/services/notebookWorkerServiceImpl.ts @@ -107,7 +107,6 @@ export class NotebookEditorModelManager extends Disposable { outputs: cell.outputs.map(op => ({ outputId: op.outputId, outputs: op.outputs })), metadata: cell.metadata })), - languages: model.languages, metadata: model.metadata } ); diff --git a/src/vs/workbench/contrib/notebook/test/notebookViewModel.test.ts b/src/vs/workbench/contrib/notebook/test/notebookViewModel.test.ts index 16b97952617..65f836cef5d 100644 --- a/src/vs/workbench/contrib/notebook/test/notebookViewModel.test.ts +++ b/src/vs/workbench/contrib/notebook/test/notebookViewModel.test.ts @@ -15,17 +15,15 @@ import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/v import { TrackedRangeStickiness } from 'vs/editor/common/model'; import { reduceCellRanges } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; -import { IModeService } from 'vs/editor/common/services/modeService'; suite('NotebookViewModel', () => { const instantiationService = setupInstantiationService(); const textModelService = instantiationService.get(ITextModelService); const blukEditService = instantiationService.get(IBulkEditService); const undoRedoService = instantiationService.get(IUndoRedoService); - const modeService = instantiationService.get(IModeService); test('ctor', function () { - const notebook = new NotebookTextModel('notebook', false, URI.parse('test'), [], [], notebookDocumentMetadataDefaults, { transientMetadata: {}, transientOutputs: false }, undoRedoService, textModelService, modeService); + const notebook = new NotebookTextModel('notebook', false, URI.parse('test'), [], notebookDocumentMetadataDefaults, { transientMetadata: {}, transientOutputs: false }, undoRedoService, textModelService); const model = new NotebookEditorTestModel(notebook); const eventDispatcher = new NotebookEventDispatcher(); const viewModel = new NotebookViewModel('notebook', model.notebook, eventDispatcher, null, instantiationService, blukEditService, undoRedoService); @@ -156,7 +154,7 @@ suite('NotebookViewModel', () => { ['var e = 5;', 'javascript', CellKind.Code, [], { editable: false, runnable: false }], ], (editor, viewModel) => { - viewModel.notebookDocument.metadata = { editable: true, runnable: true, cellRunnable: true, cellEditable: true, cellHasExecutionOrder: true, trusted: true, languages: [] }; + viewModel.notebookDocument.metadata = { editable: true, runnable: true, cellRunnable: true, cellEditable: true, cellHasExecutionOrder: true, trusted: true }; const defaults = { hasExecutionOrder: true }; @@ -190,7 +188,7 @@ suite('NotebookViewModel', () => { ...defaults }); - viewModel.notebookDocument.metadata = { editable: true, runnable: true, cellRunnable: false, cellEditable: true, cellHasExecutionOrder: true, trusted: true, languages: [] }; + viewModel.notebookDocument.metadata = { editable: true, runnable: true, cellRunnable: false, cellEditable: true, cellHasExecutionOrder: true, trusted: true }; assert.deepEqual(viewModel.viewCells[0].getEvaluatedMetadata(viewModel.metadata), { editable: true, @@ -222,7 +220,7 @@ suite('NotebookViewModel', () => { ...defaults }); - viewModel.notebookDocument.metadata = { editable: true, runnable: true, cellRunnable: false, cellEditable: false, cellHasExecutionOrder: true, trusted: true, languages: [] }; + viewModel.notebookDocument.metadata = { editable: true, runnable: true, cellRunnable: false, cellEditable: false, cellHasExecutionOrder: true, trusted: true }; assert.deepEqual(viewModel.viewCells[0].getEvaluatedMetadata(viewModel.metadata), { editable: false, diff --git a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts index b49ef38f8b2..73ed963c78b 100644 --- a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts @@ -34,7 +34,6 @@ import { TestConfigurationService } from 'vs/platform/configuration/test/common/ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; import { ScrollEvent } from 'vs/base/common/scrollable'; -import { IModeService } from 'vs/editor/common/services/modeService'; import { IFileStatWithMetadata } from 'vs/platform/files/common/files'; export class TestCell extends NotebookCellTextModel { @@ -423,7 +422,6 @@ export function setupInstantiationService() { export function withTestNotebook(instantiationService: TestInstantiationService, blukEditService: IBulkEditService, undoRedoService: IUndoRedoService, cells: [string, string, CellKind, IOutputDto[], NotebookCellMetadata][], callback: (editor: TestNotebookEditor, viewModel: NotebookViewModel, textModel: NotebookTextModel) => void) { const textModelService = instantiationService.get(ITextModelService); - const modeService = instantiationService.get(IModeService); const viewType = 'notebook'; const editor = new TestNotebookEditor(); @@ -435,7 +433,7 @@ export function withTestNotebook(instantiationService: TestInstantiationService, outputs: cell[3], metadata: cell[4] }; - }), [], notebookDocumentMetadataDefaults, { transientMetadata: {}, transientOutputs: false }, undoRedoService, textModelService, modeService); + }), notebookDocumentMetadataDefaults, { transientMetadata: {}, transientOutputs: false }, undoRedoService, textModelService); const model = new NotebookEditorTestModel(notebook); const eventDispatcher = new NotebookEventDispatcher(); const viewModel = new NotebookViewModel(viewType, model.notebook, eventDispatcher, null, instantiationService, blukEditService, undoRedoService); From d10ea1358ad5fc0c4214ce379238a47dc1e5cba6 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 11 Feb 2021 15:51:51 +0100 Subject: [PATCH 018/325] add more wordings to settings sync dialog --- src/vs/workbench/contrib/update/browser/update.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/update/browser/update.ts b/src/vs/workbench/contrib/update/browser/update.ts index 7364de67b67..1ac14573954 100644 --- a/src/vs/workbench/contrib/update/browser/update.ts +++ b/src/vs/workbench/contrib/update/browser/update.ts @@ -579,14 +579,14 @@ export class SwitchProductQualityContribution extends Disposable implements IWor private async selectSettingsSyncService(dialogService: IDialogService): Promise { const res = await dialogService.show( Severity.Info, - nls.localize('selectSyncService.message', "Choose the settings sync service to use"), + nls.localize('selectSyncService.message', "Choose the settings sync service to use after changing the version"), [ nls.localize('use insiders', "Insiders"), nls.localize('use stable', "Stable (current)"), nls.localize('cancel', "Cancel"), ], { - detail: nls.localize('selectSyncService.detail', "Switching to insiders version will synchronize your data using insiders settings sync service."), + detail: nls.localize('selectSyncService.detail', "Insiders version of VSCode will synchronize your settings, keybindings, extensions, snippets and UI State using separete insiders settings sync service by default."), cancelId: 2 } ); From 33a92ebf4aca861a1112a15b6935768bd21273b1 Mon Sep 17 00:00:00 2001 From: Damien Engels Date: Thu, 11 Feb 2021 14:48:24 +0100 Subject: [PATCH 019/325] Updates tsec to 0.1.3 This version of tsec removes a few false positives around Workers and adds support for restricting unsafe functions from the safevalues package --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cee4950e77e..cc9f055cc99 100644 --- a/package.json +++ b/package.json @@ -189,7 +189,7 @@ "source-map-support": "^0.3.2", "style-loader": "^1.0.0", "ts-loader": "^6.2.1", - "tsec": "0.1.1", + "tsec": "0.1.3", "typescript": "4.2.0-dev.20201207", "typescript-formatter": "7.1.0", "underscore": "^1.8.2", From 58eb43beaa503f638c34f1133cb01947431bbbc6 Mon Sep 17 00:00:00 2001 From: Damien Engels Date: Thu, 11 Feb 2021 14:52:48 +0100 Subject: [PATCH 020/325] List all tsec exemption explicitly This implies a few things: - tsec's output is clear so it can be included as a CI check - code introducing new violations need to update the exemption list, making it clear there is something security-sensitive about the code --- src/tsec.exemptions.json | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/tsec.exemptions.json b/src/tsec.exemptions.json index dc1e805868f..34fb2f4d8d2 100644 --- a/src/tsec.exemptions.json +++ b/src/tsec.exemptions.json @@ -1,5 +1,31 @@ { + "ban-eval-calls": [ + "vs/workbench/api/worker/extHostExtensionService.ts" + ], + "ban-function-calls": [ + "vs/workbench/api/worker/extHostExtensionService.ts", + "vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts", + "vs/workbench/services/keybinding/test/electron-browser/keyboardMapperTestUtils.ts" + ], "ban-trustedtypes-createpolicy": [ - "**/*.ts" + "vs/base/browser/dom.ts", + "vs/base/browser/markdownRenderer.ts", + "vs/base/worker/defaultWorkerFactory.ts", + "vs/base/worker/workerMain.ts", + "vs/editor/browser/core/markdownRenderer.ts", + "vs/editor/browser/view/domLineBreaksComputer.ts", + "vs/editor/browser/view/viewLayer.ts", + "vs/editor/browser/widget/diffEditorWidget.ts", + "vs/editor/browser/widget/diffReview.ts", + "vs/editor/standalone/browser/colorizer.ts", + "vs/workbench/api/worker/extHostExtensionService.ts", + "vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts", + "vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts", + "vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts", + "vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts" + ], + "ban-worker-calls": [ + "vs/base/worker/defaultWorkerFactory.ts", + "vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts" ] } From 91b533066e6f3bf091cc8b73e15d568811a737b3 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 11 Feb 2021 16:48:08 +0100 Subject: [PATCH 021/325] post merge clean-up --- src/vs/workbench/api/common/extHostTypes.ts | 4 +--- src/vs/workbench/test/browser/api/extHostTypes.test.ts | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index dac847fc2ae..1afc1dceed4 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -2896,7 +2896,6 @@ export class NotebookDocumentMetadata { readonly custom: { [key: string]: any; } = {}, readonly runState: NotebookRunState = NotebookRunState.Idle, readonly trusted: boolean = true, - readonly languages: string[] = [], ) { } with(change: Partial>) { @@ -2909,8 +2908,7 @@ export class NotebookDocumentMetadata { change.displayOrder ?? this.displayOrder, change.custom ?? this.custom, change.runState ?? this.runState, - change.trusted ?? this.trusted, - change.languages ?? this.languages, + change.trusted ?? this.trusted ); } } diff --git a/src/vs/workbench/test/browser/api/extHostTypes.test.ts b/src/vs/workbench/test/browser/api/extHostTypes.test.ts index d7d0339ed80..055c9ea4a8f 100644 --- a/src/vs/workbench/test/browser/api/extHostTypes.test.ts +++ b/src/vs/workbench/test/browser/api/extHostTypes.test.ts @@ -657,7 +657,6 @@ suite('ExtHostTypes', function () { assert.deepStrictEqual(obj.custom, notebookDocumentMetadataDefaults.custom); assert.deepStrictEqual(obj.displayOrder, notebookDocumentMetadataDefaults.displayOrder); assert.strictEqual(obj.editable, notebookDocumentMetadataDefaults.editable); - assert.deepStrictEqual(obj.languages, notebookDocumentMetadataDefaults.languages); assert.strictEqual(obj.runState, notebookDocumentMetadataDefaults.runState); assert.strictEqual(obj.runnable, notebookDocumentMetadataDefaults.runnable); assert.strictEqual(obj.trusted, notebookDocumentMetadataDefaults.trusted); From 27bdcacfabc679b1a13077254abcf76379e2d77d Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 11 Feb 2021 16:55:57 +0100 Subject: [PATCH 022/325] update distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e6c9f604c56..06107707dc0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.54.0", - "distro": "474cec03b7b7f7ea97ffd4d2748ac79a4752ab68", + "distro": "95f5b240383cb89b977a843ba09b27b72cfaf667", "author": { "name": "Microsoft Corporation" }, From cf879190e7426a5686b41f6f3ff3c0fd62b3a49c Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 11 Feb 2021 19:55:30 +0100 Subject: [PATCH 023/325] sync resource enablement keys & service key in web --- .../userDataSyncResourceEnablementService.ts | 15 ++++++++++- .../common/userDataSyncStoreService.ts | 27 ++++++++++++------- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/vs/platform/userDataSync/common/userDataSyncResourceEnablementService.ts b/src/vs/platform/userDataSync/common/userDataSyncResourceEnablementService.ts index 4fd2b3c339e..a5c7efb03e1 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncResourceEnablementService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncResourceEnablementService.ts @@ -8,6 +8,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { Emitter, Event } from 'vs/base/common/event'; import { IStorageService, IStorageValueChangeEvent, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { isWeb } from 'vs/base/common/platform'; type SyncEnablementClassification = { enabled?: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; @@ -29,6 +30,14 @@ export class UserDataSyncResourceEnablementService extends Disposable implements ) { super(); this._register(storageService.onDidChangeValue(e => this.onDidStorageChange(e))); + + for (const resource of ALL_SYNC_RESOURCES) { + const resourceEnablementKey = getEnablementKey(resource); + if (this.storageService.getBoolean(resourceEnablementKey, StorageScope.GLOBAL) === undefined) { + // Make sure the resource enablement storageKey is added to user/machine targets + this.storeResourceEnablement(resourceEnablementKey, true); + } + } } isResourceEnabled(resource: SyncResource): boolean { @@ -39,10 +48,14 @@ export class UserDataSyncResourceEnablementService extends Disposable implements if (this.isResourceEnabled(resource) !== enabled) { const resourceEnablementKey = getEnablementKey(resource); this.telemetryService.publicLog2<{ enabled: boolean }, SyncEnablementClassification>(resourceEnablementKey, { enabled }); - this.storageService.store(resourceEnablementKey, enabled, StorageScope.GLOBAL, StorageTarget.MACHINE); + this.storeResourceEnablement(resourceEnablementKey, enabled); } } + private storeResourceEnablement(resourceEnablementKey: string, enabled: boolean): void { + this.storageService.store(resourceEnablementKey, enabled, StorageScope.GLOBAL, isWeb ? StorageTarget.USER /* sync in web */ : StorageTarget.MACHINE); + } + private onDidStorageChange(storageChangeEvent: IStorageValueChangeEvent): void { if (storageChangeEvent.scope === StorageScope.GLOBAL) { const resourceKey = ALL_SYNC_RESOURCES.filter(resourceKey => getEnablementKey(resourceKey) === storageChangeEvent.key)[0]; diff --git a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts index 5c4e759cd66..259a189f0bd 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts @@ -31,7 +31,7 @@ const MACHINE_SESSION_ID_KEY = 'sync.machine-session-id'; const REQUEST_SESSION_LIMIT = 100; const REQUEST_SESSION_INTERVAL = 1000 * 60 * 5; /* 5 minutes */ -type UserDataSyncStore = IUserDataSyncStore & { defaultType?: UserDataSyncStoreType; type?: UserDataSyncStoreType }; +type UserDataSyncStore = IUserDataSyncStore & { defaultType: UserDataSyncStoreType; type: UserDataSyncStoreType }; export abstract class AbstractUserDataSyncStoreManagementService extends Disposable implements IUserDataSyncStoreManagementService { @@ -42,6 +42,13 @@ export abstract class AbstractUserDataSyncStoreManagementService extends Disposa private _userDataSyncStore: UserDataSyncStore | undefined; get userDataSyncStore(): UserDataSyncStore | undefined { return this._userDataSyncStore; } + private get userDataSyncStoreType(): UserDataSyncStoreType | undefined { + return this.storageService.get(SYNC_SERVICE_URL_TYPE, StorageScope.GLOBAL) as UserDataSyncStoreType; + } + private set userDataSyncStoreType(type: UserDataSyncStoreType | undefined) { + this.storageService.store(SYNC_SERVICE_URL_TYPE, type, StorageScope.GLOBAL, isWeb ? StorageTarget.USER /* sync in web */ : StorageTarget.MACHINE); + } + constructor( @IProductService protected readonly productService: IProductService, @IConfigurationService protected readonly configurationService: IConfigurationService, @@ -49,6 +56,9 @@ export abstract class AbstractUserDataSyncStoreManagementService extends Disposa ) { super(); this.updateUserDataSyncStore(); + + // Make sure the userDataSyncStore type storageKey is added to user/machine targets + this.userDataSyncStoreType = this.userDataSyncStore?.type; } protected updateUserDataSyncStore(): void { @@ -67,7 +77,8 @@ export abstract class AbstractUserDataSyncStoreManagementService extends Disposa ) { const syncStore = value as ConfigurationSyncStore; const canSwitch = !!syncStore.canSwitch && !configuredStore?.url; - const type: UserDataSyncStoreType | undefined = canSwitch ? this.storageService.get(SYNC_SERVICE_URL_TYPE, StorageScope.GLOBAL) as UserDataSyncStoreType : undefined; + const defaultType: UserDataSyncStoreType = syncStore.url === syncStore.insidersUrl ? 'insiders' : 'stable'; + const type: UserDataSyncStoreType = this.userDataSyncStoreType || defaultType; const url = configuredStore?.url || (type === 'insiders' ? syncStore.insidersUrl : type === 'stable' ? syncStore.stableUrl @@ -75,11 +86,11 @@ export abstract class AbstractUserDataSyncStoreManagementService extends Disposa return { url: URI.parse(url), type, - defaultType: syncStore.url === syncStore.insidersUrl ? 'insiders' : syncStore.url === syncStore.stableUrl ? 'stable' : undefined, + defaultType, defaultUrl: URI.parse(syncStore.url), stableUrl: URI.parse(syncStore.stableUrl), insidersUrl: URI.parse(syncStore.insidersUrl), - canSwitch: !!syncStore.canSwitch && !configuredStore?.url, + canSwitch, authenticationProviders: Object.keys(syncStore.authenticationProviders).reduce((result, id) => { result.push({ id, scopes: syncStore!.authenticationProviders[id].scopes }); return result; @@ -91,7 +102,7 @@ export abstract class AbstractUserDataSyncStoreManagementService extends Disposa set(type: UserDataSyncStoreType) { if (this.userDataSyncStore) { - this.storageService.store(SYNC_SERVICE_URL_TYPE, type, StorageScope.GLOBAL, StorageTarget.MACHINE); + this.userDataSyncStoreType = type; } } @@ -126,11 +137,7 @@ export class UserDataSyncStoreManagementService extends AbstractUserDataSyncStor async switch(type: UserDataSyncStoreType): Promise { if (this.userDataSyncStore?.canSwitch && type !== this.userDataSyncStore.type) { - if (type === this.userDataSyncStore.defaultType) { - this.storageService.remove(SYNC_SERVICE_URL_TYPE, StorageScope.GLOBAL); - } else { - this.set(type); - } + this.set(type); this.updateUserDataSyncStore(); } } From e21134dd71ebf8db7ea092eac94413584bdecf54 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Thu, 11 Feb 2021 11:16:38 -0800 Subject: [PATCH 024/325] testing: implement base autorun Fixes https://github.com/microsoft/vscode/issues/116383 Pending better icon with https://github.com/microsoft/vscode-codicons/issues/42 --- src/vs/base/common/iterator.ts | 12 ++ .../preferences/browser/settingsLayout.ts | 5 + .../contrib/testing/browser/icons.ts | 1 + .../contrib/testing/browser/media/testing.css | 4 + .../testing/browser/testExplorerActions.ts | 47 ++++++-- .../testing/browser/testing.contribution.ts | 7 ++ .../testing/browser/testingExplorerFilter.ts | 20 +--- .../contrib/testing/browser/theme.ts | 19 +++- .../contrib/testing/common/configuration.ts | 33 ++++++ .../testing/common/testResultService.ts | 15 +++ .../contrib/testing/common/testingAutoRun.ts | 107 ++++++++++++++++++ .../testing/common/testingContextKeys.ts | 1 + 12 files changed, 244 insertions(+), 27 deletions(-) create mode 100644 src/vs/workbench/contrib/testing/common/configuration.ts create mode 100644 src/vs/workbench/contrib/testing/common/testingAutoRun.ts diff --git a/src/vs/base/common/iterator.ts b/src/vs/base/common/iterator.ts index 7d622c76c53..adfbdc906ab 100644 --- a/src/vs/base/common/iterator.ts +++ b/src/vs/base/common/iterator.ts @@ -39,6 +39,18 @@ export namespace Iterable { return false; } + export function find(iterable: Iterable, predicate: (t: T) => t is R): T | undefined; + export function find(iterable: Iterable, predicate: (t: T) => boolean): T | undefined; + export function find(iterable: Iterable, predicate: (t: T) => boolean): T | undefined { + for (const element of iterable) { + if (predicate(element)) { + return element; + } + } + + return undefined; + } + export function filter(iterable: Iterable, predicate: (t: T) => t is R): Iterable; export function filter(iterable: Iterable, predicate: (t: T) => boolean): Iterable; export function* filter(iterable: Iterable, predicate: (t: T) => boolean): Iterable { diff --git a/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts b/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts index b6792cc7092..1e0aa909416 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts @@ -137,6 +137,11 @@ export const tocData: ITOCEntry = { label: localize('debug', "Debug"), settings: ['debug.*', 'launch'] }, + { + id: 'features/testing', + label: localize('testing', "Testing"), + settings: ['testing.*'] + }, { id: 'features/scm', label: localize('scm', "SCM"), diff --git a/src/vs/workbench/contrib/testing/browser/icons.ts b/src/vs/workbench/contrib/testing/browser/icons.ts index 6ce787cabf7..b89c7382b08 100644 --- a/src/vs/workbench/contrib/testing/browser/icons.ts +++ b/src/vs/workbench/contrib/testing/browser/icons.ts @@ -16,6 +16,7 @@ export const testingRunAllIcon = registerIcon('testing-run-all-icon', Codicon.ru export const testingDebugIcon = registerIcon('testing-debug-icon', Codicon.debugAlt, localize('testingDebugIcon', 'Icon of the "debug test" action.')); export const testingCancelIcon = registerIcon('testing-cancel-icon', Codicon.close, localize('testingCancelIcon', 'Icon to cancel ongoing test runs.')); export const testingFilterIcon = registerIcon('testing-filter', Codicon.filter, localize('filterIcon', 'Icon for the \'Filter\' action in the testing view.')); +export const testingAutorunIcon = registerIcon('testing-autorun', Codicon.symbolEvent, localize('autoRunIcon', 'Icon for the \'Autorun\' toggle in the testing view.')); export const testingShowAsList = registerIcon('testing-show-as-list-icon', Codicon.listTree, localize('testingShowAsList', 'Icon shown when the test explorer is disabled as a tree.')); export const testingShowAsTree = registerIcon('testing-show-as-list-icon', Codicon.listFlat, localize('testingShowAsTree', 'Icon shown when the test explorer is disabled as a list.')); diff --git a/src/vs/workbench/contrib/testing/browser/media/testing.css b/src/vs/workbench/contrib/testing/browser/media/testing.css index 3943b0bd98d..19896bdbd8d 100644 --- a/src/vs/workbench/contrib/testing/browser/media/testing.css +++ b/src/vs/workbench/contrib/testing/browser/media/testing.css @@ -60,6 +60,10 @@ margin-right: 8px; } +.monaco-workbench .part > .title > .title-actions .action-label.codicon-testing-autorun::before { + padding: 2px; +} + .codicon-testing-loading-icon::before { /* Use steps to throttle FPS to reduce CPU usage */ animation: codicon-spin 1.25s steps(30) infinite; diff --git a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts index 6125b257fa7..60ffcfc38c0 100644 --- a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts +++ b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts @@ -21,8 +21,9 @@ import { ViewAction } from 'vs/workbench/browser/parts/views/viewPane'; import { FocusedViewContext } from 'vs/workbench/common/views'; import * as icons from 'vs/workbench/contrib/testing/browser/icons'; import { TestingExplorerView, TestingExplorerViewModel } from 'vs/workbench/contrib/testing/browser/testingExplorerView'; -import { TestExplorerViewSorting, TestExplorerViewMode, Testing } from 'vs/workbench/contrib/testing/common/constants'; +import { TestExplorerViewMode, TestExplorerViewSorting, Testing } from 'vs/workbench/contrib/testing/common/constants'; import { InternalTestItem, TestIdWithProvider } from 'vs/workbench/contrib/testing/common/testCollection'; +import { ITestingAutoRun } from 'vs/workbench/contrib/testing/common/testingAutoRun'; import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys'; import { ITestResult, ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService'; import { ITestService, waitForAllRoots } from 'vs/workbench/contrib/testing/common/testService'; @@ -31,10 +32,16 @@ import { IWorkspaceTestCollectionService } from 'vs/workbench/contrib/testing/co const category = localize('testing.category', 'Test'); const enum ActionOrder { + // Navigation: Run = 10, Debug, - Refresh, + AutoRun, Collapse, + + // Submenu: + DisplayMode, + Sort, + Refresh, } export class DebugAction extends Action { @@ -287,7 +294,7 @@ export class TestingViewAsListAction extends ViewAction { toggled: TestingContextKeys.viewMode.isEqualTo(TestExplorerViewMode.List), menu: { id: MenuId.ViewTitle, - order: 10, + order: ActionOrder.DisplayMode, group: 'viewAs', when: ContextKeyEqualsExpr.create('view', Testing.ExplorerViewId) } @@ -312,7 +319,7 @@ export class TestingViewAsTreeAction extends ViewAction { toggled: TestingContextKeys.viewMode.isEqualTo(TestExplorerViewMode.Tree), menu: { id: MenuId.ViewTitle, - order: 10, + order: ActionOrder.DisplayMode, group: 'viewAs', when: ContextKeyEqualsExpr.create('view', Testing.ExplorerViewId) } @@ -338,7 +345,7 @@ export class TestingSortByNameAction extends ViewAction { toggled: TestingContextKeys.viewSorting.isEqualTo(TestExplorerViewSorting.ByName), menu: { id: MenuId.ViewTitle, - order: 10, + order: ActionOrder.Sort, group: 'sortBy', when: ContextKeyEqualsExpr.create('view', Testing.ExplorerViewId) } @@ -363,7 +370,7 @@ export class TestingSortByLocationAction extends ViewAction toggled: TestingContextKeys.viewSorting.isEqualTo(TestExplorerViewSorting.ByLocation), menu: { id: MenuId.ViewTitle, - order: 10, + order: ActionOrder.Sort, group: 'sortBy', when: ContextKeyEqualsExpr.create('view', Testing.ExplorerViewId) } @@ -410,11 +417,10 @@ export class RefreshTestsAction extends Action2 { title: localize('testing.refresh', "Refresh Tests"), category, f1: true, - icon: Codicon.refresh, menu: { id: MenuId.ViewTitle, order: ActionOrder.Refresh, - group: 'navigation', + group: 'refresh', when: ContextKeyEqualsExpr.create('view', Testing.ExplorerViewId) } }); @@ -471,3 +477,28 @@ export class EditFocusedTest extends ViewAction { } } } + +export class ToggleAutoRun extends Action2 { + constructor() { + super({ + id: 'testing.toggleautoRun', + title: localize('testing.toggleautoRun', "Toggle Auto Run"), + f1: true, + toggled: TestingContextKeys.autoRun.isEqualTo(true), + icon: icons.testingAutorunIcon, + menu: { + id: MenuId.ViewTitle, + order: ActionOrder.AutoRun, + group: 'navigation', + when: ContextKeyEqualsExpr.create('view', Testing.ExplorerViewId) + } + }); + } + + /** + * @override + */ + public run(accessor: ServicesAccessor) { + accessor.get(ITestingAutoRun).toggle(); + } +} diff --git a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts index c98cf48cb5c..3cbf194564e 100644 --- a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts +++ b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts @@ -7,6 +7,7 @@ import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { localize } from 'vs/nls'; import { registerAction2 } from 'vs/platform/actions/common/actions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; @@ -20,8 +21,10 @@ import { ITestExplorerFilterState, TestExplorerFilterState } from 'vs/workbench/ import { TestingExplorerView } from 'vs/workbench/contrib/testing/browser/testingExplorerView'; import { CloseTestPeek, TestingOutputPeekController } from 'vs/workbench/contrib/testing/browser/testingOutputPeek'; import { TestingViewPaneContainer } from 'vs/workbench/contrib/testing/browser/testingViewPaneContainer'; +import { testingConfiguation } from 'vs/workbench/contrib/testing/common/configuration'; import { Testing } from 'vs/workbench/contrib/testing/common/constants'; import { TestIdWithProvider } from 'vs/workbench/contrib/testing/common/testCollection'; +import { ITestingAutoRun, TestingAutoRun } from 'vs/workbench/contrib/testing/common/testingAutoRun'; import { TestingContentProvider } from 'vs/workbench/contrib/testing/common/testingContentProvider'; import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys'; import { ITestResultService, TestResultService } from 'vs/workbench/contrib/testing/common/testResultService'; @@ -34,6 +37,7 @@ import * as Action from './testExplorerActions'; registerSingleton(ITestService, TestService); registerSingleton(ITestResultService, TestResultService); registerSingleton(ITestExplorerFilterState, TestExplorerFilterState); +registerSingleton(ITestingAutoRun, TestingAutoRun, true); registerSingleton(IWorkspaceTestCollectionService, WorkspaceTestCollectionService); const viewContainer = Registry.as(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer({ @@ -91,6 +95,7 @@ registerAction2(Action.RunAllAction); registerAction2(Action.DebugAllAction); registerAction2(Action.EditFocusedTest); registerAction2(Action.ClearTestResultsAction); +registerAction2(Action.ToggleAutoRun); registerAction2(CloseTestPeek); Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TestingContentProvider, LifecyclePhase.Eventually); @@ -121,3 +126,5 @@ CommandsRegistry.registerCommand({ accessor.get(IViewsService).openView(Testing.ExplorerViewId); } }); + +Registry.as(ConfigurationExtensions.Configuration).registerConfiguration(testingConfiguation); diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts index ed9186220ae..eae8ec3d55d 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts @@ -11,7 +11,7 @@ import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdown import { HistoryInputBox } from 'vs/base/browser/ui/inputbox/inputBox'; import { Action, IAction, IActionRunner } from 'vs/base/common/actions'; import { Delayer } from 'vs/base/common/async'; -import { Event, Emitter } from 'vs/base/common/event'; +import { Emitter, Event } from 'vs/base/common/event'; import { KeyCode } from 'vs/base/common/keyCodes'; import { localize } from 'vs/nls'; import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; @@ -20,9 +20,8 @@ import { ContextKeyEqualsExpr, ContextKeyExpr } from 'vs/platform/contextkey/com import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; -import { inputActiveOptionBorder, inputActiveOptionForeground, inputActiveOptionBackground } from 'vs/platform/theme/common/colorRegistry'; import { attachInputBoxStyler } from 'vs/platform/theme/common/styler'; -import { IColorTheme, ICssStyleCollector, IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService'; +import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService'; import { ViewContainerLocation } from 'vs/workbench/common/views'; import { testingFilterIcon } from 'vs/workbench/contrib/testing/browser/icons'; import { Testing } from 'vs/workbench/contrib/testing/common/constants'; @@ -232,18 +231,3 @@ registerAction2(class extends Action2 { } async run(): Promise { } }); - -registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => { - const inputActiveOptionBorderColor = theme.getColor(inputActiveOptionBorder); - if (inputActiveOptionBorderColor) { - collector.addRule(`.testing-filter-button.checked { border-color: ${inputActiveOptionBorderColor}; }`); - } - const inputActiveOptionForegroundColor = theme.getColor(inputActiveOptionForeground); - if (inputActiveOptionForegroundColor) { - collector.addRule(`.testing-filter-button.checked { color: ${inputActiveOptionForegroundColor}; }`); - } - const inputActiveOptionBackgroundColor = theme.getColor(inputActiveOptionBackground); - if (inputActiveOptionBackgroundColor) { - collector.addRule(`.testing-filter-button.checked { background-color: ${inputActiveOptionBackgroundColor}; }`); - } -}); diff --git a/src/vs/workbench/contrib/testing/browser/theme.ts b/src/vs/workbench/contrib/testing/browser/theme.ts index dfd5607d854..3c80d02eae0 100644 --- a/src/vs/workbench/contrib/testing/browser/theme.ts +++ b/src/vs/workbench/contrib/testing/browser/theme.ts @@ -5,7 +5,7 @@ import { Color, RGBA } from 'vs/base/common/color'; import { localize } from 'vs/nls'; -import { editorErrorForeground, editorForeground, editorHintForeground, editorInfoForeground, editorWarningForeground, registerColor } from 'vs/platform/theme/common/colorRegistry'; +import { editorErrorForeground, editorForeground, editorHintForeground, editorInfoForeground, editorWarningForeground, inputActiveOptionBackground, inputActiveOptionBorder, inputActiveOptionForeground, registerColor } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { TestMessageSeverity, TestRunState } from 'vs/workbench/api/common/extHostTypes'; @@ -124,9 +124,26 @@ export const testStatesToIconColors: { [K in TestRunState]?: string } = { registerThemingParticipant((theme, collector) => { + //#region test states for (const [state, { marginBackground }] of Object.entries(testMessageSeverityColors)) { collector.addRule(`.monaco-editor .testing-inline-message-severity-${state} { background: ${theme.getColor(marginBackground)}; }`); } + //#endregion test states + + //#region active buttons + const inputActiveOptionBorderColor = theme.getColor(inputActiveOptionBorder); + if (inputActiveOptionBorderColor) { + collector.addRule(`.testing-filter-button.checked, .codicon-testing-autorun.checked::before { border-color: ${inputActiveOptionBorderColor}; }`); + } + const inputActiveOptionForegroundColor = theme.getColor(inputActiveOptionForeground); + if (inputActiveOptionForegroundColor) { + collector.addRule(`.testing-filter-button.checked, .codicon-testing-autorun.checked::before { color: ${inputActiveOptionForegroundColor}; }`); + } + const inputActiveOptionBackgroundColor = theme.getColor(inputActiveOptionBackground); + if (inputActiveOptionBackgroundColor) { + collector.addRule(`.testing-filter-button.checked, .codicon-testing-autorun.checked::before { background-color: ${inputActiveOptionBackgroundColor}; }`); + } + //#endregion }); diff --git a/src/vs/workbench/contrib/testing/common/configuration.ts b/src/vs/workbench/contrib/testing/common/configuration.ts new file mode 100644 index 00000000000..0630b3f40ac --- /dev/null +++ b/src/vs/workbench/contrib/testing/common/configuration.ts @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { localize } from 'vs/nls'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationNode } from 'vs/platform/configuration/common/configurationRegistry'; + +export const enum TestingConfigKeys { + AutoRunDelay = 'testing.autoRun.delay' +} + +export const testingConfiguation: IConfigurationNode = { + id: 'testing', + order: 21, + title: localize('testConfigurationTitle', "Testing"), + type: 'object', + properties: { + [TestingConfigKeys.AutoRunDelay]: { + type: 'integer', + minimum: 0, + description: localize('testing.autoRun.delay', "How long to wait, in milliseconds, after a test is marked as outdated and starting a new run."), + default: 1000, + }, + } +}; + +export interface ITestingConfiguration { + [TestingConfigKeys.AutoRunDelay]: number; +} + +export const getTestingConfiguration = (config: IConfigurationService, key: K) => config.getValue(key); diff --git a/src/vs/workbench/contrib/testing/common/testResultService.ts b/src/vs/workbench/contrib/testing/common/testResultService.ts index be1377587a1..bc2cbda0ca8 100644 --- a/src/vs/workbench/contrib/testing/common/testResultService.ts +++ b/src/vs/workbench/contrib/testing/common/testResultService.ts @@ -189,9 +189,11 @@ export class LiveTestResult implements ITestResult { } private readonly completeEmitter = new Emitter(); + private readonly retireEmitter = new Emitter(); private readonly changeEmitter = new Emitter(); private _complete = false; + public readonly onRetired = this.retireEmitter.event; public readonly onChange = this.changeEmitter.event; public readonly onComplete = this.completeEmitter.event; @@ -311,6 +313,7 @@ export class LiveTestResult implements ITestResult { return; } + this.retireEmitter.fire(root); const queue: Iterable[] = [[root.id]]; while (queue.length) { for (const id of queue.pop()!) { @@ -428,6 +431,11 @@ export interface ITestResultService { */ readonly onTestChanged: Event<[results: ITestResult, item: TestResultItem]>; + /** + * Fired when a test is retired, in addition to `onTestChanged`. + */ + readonly onTestRetired: Event; + /** * List of known test results. */ @@ -461,6 +469,7 @@ const RETAIN_LAST_RESULTS = 64; export class TestResultService implements ITestResultService { declare _serviceBrand: undefined; private changeResultEmitter = new Emitter(); + private testRetiredEmitter = new Emitter(); private testChangeEmitter = new Emitter<[results: ITestResult, item: TestResultItem]>(); /** @@ -478,6 +487,11 @@ export class TestResultService implements ITestResultService { */ public readonly onTestChanged = this.testChangeEmitter.event; + /** + * @inheritdoc + */ + public readonly onTestRetired = this.testRetiredEmitter.event; + private readonly isRunning: IContextKey; private readonly serializedResults: StoredValue; @@ -519,6 +533,7 @@ export class TestResultService implements ITestResultService { result.onComplete(() => this.onComplete(result)); result.onChange(t => this.testChangeEmitter.fire([result, t]), this.testChangeEmitter); + result.onRetired(this.testRetiredEmitter.fire, this.testRetiredEmitter); this.isRunning.set(true); this.changeResultEmitter.fire({ started: result }); result.setAllToState(queuedState, () => true); diff --git a/src/vs/workbench/contrib/testing/common/testingAutoRun.ts b/src/vs/workbench/contrib/testing/common/testingAutoRun.ts new file mode 100644 index 00000000000..360bbf09c31 --- /dev/null +++ b/src/vs/workbench/contrib/testing/common/testingAutoRun.ts @@ -0,0 +1,107 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { mapFind } from 'vs/base/common/arrays'; +import { RunOnceScheduler } from 'vs/base/common/async'; +import { Iterable } from 'vs/base/common/iterator'; +import { Disposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { getTestingConfiguration, TestingConfigKeys } from 'vs/workbench/contrib/testing/common/configuration'; +import { TestIdWithProvider } from 'vs/workbench/contrib/testing/common/testCollection'; +import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys'; +import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService'; +import { ITestService } from 'vs/workbench/contrib/testing/common/testService'; +import { IWorkspaceTestCollectionService } from 'vs/workbench/contrib/testing/common/workspaceTestCollectionService'; + +export interface ITestingAutoRun { + /** + * Toggles autorun on or off. + */ + toggle(): void; +} + +export const ITestingAutoRun = createDecorator('testingAutoRun'); + +export class TestingAutoRun extends Disposable implements ITestingAutoRun { + private enabled: IContextKey; + private runner = this._register(new MutableDisposable()); + + constructor( + @IContextKeyService contextKeyService: IContextKeyService, + @IWorkspaceTestCollectionService private readonly workspaceTests: IWorkspaceTestCollectionService, + @ITestService private readonly testService: ITestService, + @ITestResultService private readonly results: ITestResultService, + @IConfigurationService private readonly configuration: IConfigurationService, + ) { + super(); + this.enabled = TestingContextKeys.autoRun.bindTo(contextKeyService); + } + + /** + * @inheritdoc + */ + public toggle(): void { + const enabled = this.enabled.get(); + if (enabled) { + this.runner.value = undefined; + } else { + this.runner.value = this.makeRunner(); + } + + this.enabled.set(!enabled); + } + + /** + * Creates the runner. Is triggered when tests are marked as retired. + * Runs them on a debounce. + * + * We keep a workspace subscription open and try to find always find + * tests in the workspace -- as opposed to document tests. This is needed + * because a user could trigger a test run from a document, but close that + * document and edit another file that would cause the test to be retired. + */ + private makeRunner() { + let isRunning = false; + const rerunIds = new Map(); + const store = new DisposableStore(); + + let delay = getTestingConfiguration(this.configuration, TestingConfigKeys.AutoRunDelay); + + store.add(this.configuration.onDidChangeConfiguration(evt => { + delay = getTestingConfiguration(this.configuration, TestingConfigKeys.AutoRunDelay); + })); + + const workspaceTests = store.add(this.workspaceTests.subscribeToWorkspaceTests()); + + const scheduler = store.add(new RunOnceScheduler(async () => { + const tests = [...rerunIds.values()]; + + isRunning = true; + rerunIds.clear(); + await this.testService.runTests({ debug: false, tests }); + isRunning = false; + + if (rerunIds.size > 0) { + scheduler.schedule(delay); + } + }, delay)); + + store.add(this.results.onTestRetired(test => { + const workspaceTest = mapFind(workspaceTests.workspaceFolderCollections, + ([, c]) => c.getNodeById(test.id) ?? Iterable.find(c.all, t => t.item.extId === test.item.extId)); + const subject = workspaceTest ?? test; + + rerunIds.set(subject.id, ({ testId: subject.id, providerId: subject.providerId })); + + if (!isRunning) { + scheduler.schedule(delay); + } + })); + + return store; + } +} diff --git a/src/vs/workbench/contrib/testing/common/testingContextKeys.ts b/src/vs/workbench/contrib/testing/common/testingContextKeys.ts index a7cbbb57a0e..3a1f40ad723 100644 --- a/src/vs/workbench/contrib/testing/common/testingContextKeys.ts +++ b/src/vs/workbench/contrib/testing/common/testingContextKeys.ts @@ -15,4 +15,5 @@ export namespace TestingContextKeys { export const isInPeek = new RawContextKey('testing.isInPeek', true); export const isPeekVisible = new RawContextKey('testing.isPeekVisible', false); export const explorerLocation = new RawContextKey('testing.explorerLocation', ViewContainerLocation.Sidebar); + export const autoRun = new RawContextKey('testing.autoRun', false); } From 78de6c64b036b75b425d1be07b90a78dfbf47852 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 11 Feb 2021 20:56:19 +0100 Subject: [PATCH 025/325] remove get*Actions on container --- src/vs/workbench/browser/panecomposite.ts | 48 +++++++++++++-- .../browser/parts/views/viewPaneContainer.ts | 60 ++++--------------- 2 files changed, 53 insertions(+), 55 deletions(-) diff --git a/src/vs/workbench/browser/panecomposite.ts b/src/vs/workbench/browser/panecomposite.ts index 700678c478a..9113801e2a0 100644 --- a/src/vs/workbench/browser/panecomposite.ts +++ b/src/vs/workbench/browser/panecomposite.ts @@ -13,9 +13,10 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { Composite } from 'vs/workbench/browser/composite'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { ViewPaneContainer } from './parts/views/viewPaneContainer'; +import { ViewPaneContainer, ViewsSubMenu } from './parts/views/viewPaneContainer'; import { IPaneComposite } from 'vs/workbench/common/panecomposite'; -import { IAction, IActionViewItem } from 'vs/base/common/actions'; +import { IAction, IActionViewItem, Separator } from 'vs/base/common/actions'; +import { SubmenuItemAction } from 'vs/platform/actions/common/actions'; export abstract class PaneComposite extends Composite implements IPaneComposite { @@ -66,15 +67,52 @@ export abstract class PaneComposite extends Composite implements IPaneComposite } getContextMenuActions(): ReadonlyArray { - return this.viewPaneContainer?.getContextMenuActions() ?? []; + return this.viewPaneContainer?.menuActions?.getContextMenuActions() ?? []; } getActions(): ReadonlyArray { - return this.viewPaneContainer?.getActions() ?? []; + const result = []; + if (this.viewPaneContainer?.menuActions) { + result.push(...this.viewPaneContainer.menuActions.getPrimaryActions()); + if (this.viewPaneContainer.isViewMergedWithContainer()) { + result.push(...this.viewPaneContainer.panes[0].menuActions.getPrimaryActions()); + } + } + return result; } getSecondaryActions(): ReadonlyArray { - return this.viewPaneContainer?.getSecondaryActions() ?? []; + if (!this.viewPaneContainer?.menuActions) { + return []; + } + + const viewPaneActions = this.viewPaneContainer.isViewMergedWithContainer() ? this.viewPaneContainer.panes[0].menuActions.getSecondaryActions() : []; + let menuActions = this.viewPaneContainer.menuActions.getSecondaryActions(); + + const viewsSubmenuActionIndex = menuActions.findIndex(action => action instanceof SubmenuItemAction && action.item.submenu === ViewsSubMenu); + if (viewsSubmenuActionIndex !== -1) { + const viewsSubmenuAction = menuActions[viewsSubmenuActionIndex]; + if (viewsSubmenuAction.actions.some(({ enabled }) => enabled)) { + if (menuActions.length === 1 && viewPaneActions.length === 0) { + menuActions = viewsSubmenuAction.actions.slice(); + } else if (viewsSubmenuActionIndex !== 0) { + menuActions = [viewsSubmenuAction, ...menuActions.slice(0, viewsSubmenuActionIndex), ...menuActions.slice(viewsSubmenuActionIndex + 1)]; + } + } else { + // Remove views submenu if none of the actions are enabled + menuActions.splice(viewsSubmenuActionIndex, 1); + } + } + + if (menuActions.length && viewPaneActions.length) { + return [ + ...menuActions, + new Separator(), + ...viewPaneActions + ]; + } + + return menuActions.length ? menuActions : viewPaneActions; } getActionViewItem(action: IAction): IActionViewItem | undefined { diff --git a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts index f4b875cd080..21d60451af4 100644 --- a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts +++ b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts @@ -11,7 +11,7 @@ import { attachStyler, IColorMapping } 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_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 { EventType, Dimension, addDisposableListener, isAncestor } from 'vs/base/browser/dom'; import { IDisposable, combinedDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; -import { IAction, IActionViewItem, Separator } from 'vs/base/common/actions'; +import { IAction, IActionViewItem } from 'vs/base/common/actions'; 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'; @@ -28,7 +28,7 @@ import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewl 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 { registerAction2, Action2, IAction2Options, MenuId, MenuRegistry, ISubmenuItem, SubmenuItemAction, IMenuService } from 'vs/platform/actions/common/actions'; +import { registerAction2, Action2, IAction2Options, MenuId, MenuRegistry, ISubmenuItem, IMenuService } from 'vs/platform/actions/common/actions'; import { CompositeDragAndDropObserver, DragAndDropObserver, toggleDropEffect } from 'vs/workbench/browser/dnd'; import { Orientation } from 'vs/base/browser/ui/sash/sash'; import { RunOnceScheduler } from 'vs/base/common/async'; @@ -354,7 +354,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer { return assertIsDefined(this.paneview).onDidSashChange; } - protected get panes(): ViewPane[] { + get panes(): ViewPane[] { return this.paneItems.map(i => i.pane); } @@ -366,7 +366,10 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer { return this.paneItems.length; } - private menuActions!: ViewContainerMenuActions; + private _menuActions?: ViewContainerMenuActions; + get menuActions(): CompositeMenuActions | undefined { + return this._menuActions; + } constructor( id: string, @@ -405,8 +408,8 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer { this._register(this.paneview.onDidDrop(({ from, to }) => this.movePane(from as ViewPane, to as ViewPane))); this._register(addDisposableListener(parent, EventType.CONTEXT_MENU, (e: MouseEvent) => this.showContextMenu(new StandardMouseEvent(e)))); - this.menuActions = this._register(this.instantiationService.createInstance(ViewContainerMenuActions, this.paneview.element, this.viewContainer)); - this._register(this.menuActions.onDidChange(() => this.updateTitleArea())); + this._menuActions = this._register(this.instantiationService.createInstance(ViewContainerMenuActions, this.paneview.element, this.viewContainer)); + this._register(this._menuActions.onDidChange(() => this.updateTitleArea())); let overlay: ViewPaneDropOverlay | undefined; const getOverlayBounds: () => BoundingRect = () => { @@ -571,53 +574,10 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer { let anchor: { x: number, y: number; } = { x: event.posx, y: event.posy }; this.contextMenuService.showContextMenu({ getAnchor: () => anchor, - getActions: () => [...this.getContextMenuActions()] + getActions: () => this.menuActions?.getContextMenuActions() ?? [] }); } - getContextMenuActions(): ReadonlyArray { - return this.menuActions.getContextMenuActions(); - } - - getActions(): IAction[] { - const result = []; - result.push(...this.menuActions.getPrimaryActions()); - if (this.isViewMergedWithContainer()) { - result.push(...this.paneItems[0].pane.menuActions.getPrimaryActions()); - } - return result; - } - - getSecondaryActions(): IAction[] { - const viewPaneActions = this.isViewMergedWithContainer() ? this.paneItems[0].pane.menuActions.getSecondaryActions() : []; - let menuActions = this.menuActions.getSecondaryActions(); - - const viewsSubmenuActionIndex = menuActions.findIndex(action => action instanceof SubmenuItemAction && action.item.submenu === ViewsSubMenu); - if (viewsSubmenuActionIndex !== -1) { - const viewsSubmenuAction = menuActions[viewsSubmenuActionIndex]; - if (viewsSubmenuAction.actions.some(({ enabled }) => enabled)) { - if (menuActions.length === 1 && viewPaneActions.length === 0) { - menuActions = viewsSubmenuAction.actions.slice(); - } else if (viewsSubmenuActionIndex !== 0) { - menuActions = [viewsSubmenuAction, ...menuActions.slice(0, viewsSubmenuActionIndex), ...menuActions.slice(viewsSubmenuActionIndex + 1)]; - } - } else { - // Remove views submenu if none of the actions are enabled - menuActions.splice(viewsSubmenuActionIndex, 1); - } - } - - if (menuActions.length && viewPaneActions.length) { - return [ - ...menuActions, - new Separator(), - ...viewPaneActions - ]; - } - - return menuActions.length ? menuActions : viewPaneActions; - } - getActionsContext(): unknown { return undefined; } From d10f2e60328ebe6cbe51e1e3b213913b867680fe Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Thu, 11 Feb 2021 12:34:03 -0800 Subject: [PATCH 026/325] Fix #116412: Use getting started page as default startupEditor. --- .../welcome/gettingStarted/browser/gettingStarted.ts | 8 ++++++-- .../welcome/page/browser/welcomePage.contribution.ts | 2 +- .../welcome/walkThrough/browser/walkThroughPart.ts | 1 + test/automation/src/application.ts | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts index bed7ba568fb..f7c6019924c 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts @@ -270,7 +270,11 @@ export class GettingStartedPage extends EditorPane { ); const gettingStartedPage = - $('.gettingStarted', { role: 'document' }, + $('.gettingStarted.welcomePageFocusElement', { + role: 'document', + tabIndex: '0', + 'aria-label': localize('gettingStartedLabel', "Getting Started. Overview of how to get up to speed with your editor.") + }, $('.gettingStartedSlideCategory.gettingStartedSlide.categories'), tasksSlide ); @@ -344,7 +348,6 @@ export class GettingStartedPage extends EditorPane { this.setSlide('details'); this.buildCategorySlide(this.editorInput.selectedCategory, this.editorInput.selectedTask); } else { - this.focusFirstUncompletedCategory(); this.setSlide('categories'); } } @@ -521,6 +524,7 @@ export class GettingStartedPage extends EditorPane { slideManager.classList.add('showCategories'); this.container.querySelector('.gettingStartedSlideDetails')!.querySelectorAll('button').forEach(button => button.disabled = true); this.container.querySelector('.gettingStartedSlideCategory')!.querySelectorAll('button').forEach(button => button.disabled = false); + (this.container.querySelector('.welcomePageFocusElement') as HTMLElement)?.focus(); } else { slideManager.classList.add('showDetails'); slideManager.classList.remove('showCategories'); diff --git a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts index d49c5f3c91d..e65b6f5b462 100644 --- a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts +++ b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts @@ -30,7 +30,7 @@ Registry.as(ConfigurationExtensions.Configuration) localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.welcomePageInEmptyWorkbench' }, "Open the Welcome page when opening an empty workbench."), localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.gettingStarted' }, "Open the Getting Started page.")] ], - 'default': 'welcomePage', + 'default': 'gettingStarted', 'description': localize('workbench.startupEditor', "Controls which editor is shown at startup, if none are restored from the previous session.") }, } diff --git a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts index 5422d519840..5f06b8c2b02 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts @@ -92,6 +92,7 @@ export class WalkThroughPart extends EditorPane { createEditor(container: HTMLElement): void { this.content = document.createElement('div'); + this.content.classList.add('welcomePageFocusElement'); this.content.tabIndex = 0; this.content.style.outlineStyle = 'none'; diff --git a/test/automation/src/application.ts b/test/automation/src/application.ts index 0440d68d4e5..066b8f63fde 100644 --- a/test/automation/src/application.ts +++ b/test/automation/src/application.ts @@ -73,7 +73,7 @@ export class Application { await this.code.waitForElement('.explorer-folders-view'); if (expectWalkthroughPart) { - await this.code.waitForActiveElement(`.editor-instance[data-editor-id="workbench.editor.walkThroughPart"] > div > div[tabIndex="0"]`); + await this.code.waitForActiveElement(`.editor-instance > div > div.welcomePageFocusElement[tabIndex="0"]`); } } From 3ba5101f27f3ada74bbe0853f6cefc7e13d90486 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Thu, 11 Feb 2021 12:55:43 -0800 Subject: [PATCH 027/325] Make notebook scrollbar transparent --- .../contrib/notebook/browser/notebookEditorWidget.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 0d10b5b0f56..8a43abdf6d7 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -2466,22 +2466,19 @@ registerThemingParticipant((theme, collector) => { const scrollbarSliderBackgroundColor = theme.getColor(listScrollbarSliderBackground); if (scrollbarSliderBackgroundColor) { - collector.addRule(` .notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .scrollbar > .slider { background: ${editorBackgroundColor}; } `); - collector.addRule(` .notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .scrollbar > .slider:before { content: ""; width: 100%; height: 100%; position: absolute; background: ${scrollbarSliderBackgroundColor}; } `); /* hack to not have cells see through scroller */ + collector.addRule(` .notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .scrollbar > .slider { background: ${scrollbarSliderBackgroundColor}; } `); // collector.addRule(` .monaco-workbench .notebookOverlay .output-plaintext::-webkit-scrollbar-track { background: ${scrollbarSliderBackgroundColor}; } `); } const scrollbarSliderHoverBackgroundColor = theme.getColor(listScrollbarSliderHoverBackground); if (scrollbarSliderHoverBackgroundColor) { - collector.addRule(` .notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .scrollbar > .slider:hover { background: ${editorBackgroundColor}; } `); - collector.addRule(` .notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .scrollbar > .slider:hover:before { content: ""; width: 100%; height: 100%; position: absolute; background: ${scrollbarSliderHoverBackgroundColor}; } `); /* hack to not have cells see through scroller */ + collector.addRule(` .notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .scrollbar > .slider:hover { background: ${scrollbarSliderHoverBackgroundColor}; } `); collector.addRule(` .monaco-workbench .notebookOverlay .output-plaintext::-webkit-scrollbar-thumb { background: ${scrollbarSliderHoverBackgroundColor}; } `); } const scrollbarSliderActiveBackgroundColor = theme.getColor(listScrollbarSliderActiveBackground); if (scrollbarSliderActiveBackgroundColor) { - collector.addRule(` .notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .scrollbar > .slider.active { background: ${editorBackgroundColor}; } `); - collector.addRule(` .notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .scrollbar > .slider.active:before { content: ""; width: 100%; height: 100%; position: absolute; background: ${scrollbarSliderActiveBackgroundColor}; } `); /* hack to not have cells see through scroller */ + collector.addRule(` .notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .scrollbar > .slider.active { background: ${scrollbarSliderActiveBackgroundColor}; } `); } // case ChangeType.Modify: return theme.getColor(editorGutterModifiedBackground); From a7758e4328b2519e1e497f9b58d801a0de534728 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Thu, 11 Feb 2021 13:43:42 -0800 Subject: [PATCH 028/325] Update indicator height for collapsed cells --- .../contrib/notebook/browser/viewModel/codeCellViewModel.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts index d3fbea6a477..c59b6d52458 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts @@ -131,7 +131,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod } const statusbarHeight = this.getEditorStatusbarHeight(); - const indicatorHeight = editorHeight + statusbarHeight + outputTotalHeight + outputShowMoreContainerHeight + (CELL_TOP_MARGIN * 2); + const indicatorHeight = editorHeight + statusbarHeight + outputTotalHeight + outputShowMoreContainerHeight + CELL_TOP_MARGIN + CELL_BOTTOM_MARGIN; const outputContainerOffset = EDITOR_TOOLBAR_HEIGHT + CELL_TOP_MARGIN + editorHeight + statusbarHeight; const outputShowMoreContainerOffset = totalHeight - BOTTOM_CELL_TOOLBAR_GAP - BOTTOM_CELL_TOOLBAR_HEIGHT / 2 - outputShowMoreContainerHeight; const bottomToolbarOffset = totalHeight - BOTTOM_CELL_TOOLBAR_GAP - BOTTOM_CELL_TOOLBAR_HEIGHT / 2; @@ -152,7 +152,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod }; } else { outputTotalHeight = this.metadata?.inputCollapsed && this.metadata.outputCollapsed ? 0 : outputTotalHeight; - const indicatorHeight = COLLAPSED_INDICATOR_HEIGHT + outputTotalHeight + outputShowMoreContainerHeight; + const indicatorHeight = COLLAPSED_INDICATOR_HEIGHT + outputTotalHeight + outputShowMoreContainerHeight + CELL_TOP_MARGIN + CELL_BOTTOM_MARGIN; const outputContainerOffset = CELL_TOP_MARGIN + COLLAPSED_INDICATOR_HEIGHT; const totalHeight = CELL_TOP_MARGIN + COLLAPSED_INDICATOR_HEIGHT + CELL_BOTTOM_MARGIN + BOTTOM_CELL_TOOLBAR_GAP + outputTotalHeight + outputShowMoreContainerHeight; const outputShowMoreContainerOffset = totalHeight - BOTTOM_CELL_TOOLBAR_GAP - BOTTOM_CELL_TOOLBAR_HEIGHT / 2 - outputShowMoreContainerHeight; From 650906c3697b1ce2b9e6406a5a9bafdb93ee4771 Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Thu, 11 Feb 2021 12:28:17 -0800 Subject: [PATCH 029/325] Pass scopes through to authentication providers --- .../github-authentication/src/common/utils.ts | 22 ++++++++++++++++ .../github-authentication/src/extension.ts | 3 ++- .../github-authentication/src/github.ts | 5 ++++ .../microsoft-authentication/src/AADHelper.ts | 6 +++++ .../microsoft-authentication/src/extension.ts | 3 ++- src/vs/vscode.proposed.d.ts | 11 +++++++- .../api/browser/mainThreadAuthentication.ts | 25 ++++++++----------- .../workbench/api/common/extHost.protocol.ts | 4 +-- .../api/common/extHostAuthentication.ts | 14 +++-------- .../parts/activitybar/activitybarActions.ts | 2 +- .../issue/electron-sandbox/issueService.ts | 2 +- .../contrib/url/browser/trustedDomains.ts | 2 +- .../browser/authenticationService.ts | 20 +++++++++++---- .../browser/userDataSyncWorkbenchService.ts | 2 +- 14 files changed, 82 insertions(+), 39 deletions(-) diff --git a/extensions/github-authentication/src/common/utils.ts b/extensions/github-authentication/src/common/utils.ts index b6fc3361315..6ebfe7b08b3 100644 --- a/extensions/github-authentication/src/common/utils.ts +++ b/extensions/github-authentication/src/common/utils.ts @@ -71,3 +71,25 @@ export async function promiseFromEvent( } ); } + +export function arrayEquals(one: ReadonlyArray | undefined, other: ReadonlyArray | undefined, itemEquals: (a: T, b: T) => boolean = (a, b) => a === b): boolean { + if (one === other) { + return true; + } + + if (!one || !other) { + return false; + } + + if (one.length !== other.length) { + return false; + } + + for (let i = 0, len = one.length; i < len; i++) { + if (!itemEquals(one[i], other[i])) { + return false; + } + } + + return true; +} diff --git a/extensions/github-authentication/src/extension.ts b/extensions/github-authentication/src/extension.ts index fd981fb3fe8..bd41ea45535 100644 --- a/extensions/github-authentication/src/extension.ts +++ b/extensions/github-authentication/src/extension.ts @@ -24,7 +24,8 @@ export async function activate(context: vscode.ExtensionContext) { context.subscriptions.push(vscode.authentication.registerAuthenticationProvider('github', 'GitHub', { onDidChangeSessions: onDidChangeSessions.event, - getSessions: () => Promise.resolve(loginService.sessions), + getAllSessions: () => Promise.resolve(loginService.sessions), + getSessions: (scopes: string[]) => loginService.getSessions(scopes), login: async (scopeList: string[]) => { try { /* __GDPR__ diff --git a/extensions/github-authentication/src/github.ts b/extensions/github-authentication/src/github.ts index 250a7bdfd00..f3ef508cd5c 100644 --- a/extensions/github-authentication/src/github.ts +++ b/extensions/github-authentication/src/github.ts @@ -8,6 +8,7 @@ import { v4 as uuid } from 'uuid'; import { Keychain } from './common/keychain'; import { GitHubServer, NETWORK_ERROR } from './githubServer'; import Logger from './common/logger'; +import { arrayEquals } from './common/utils'; export const onDidChangeSessions = new vscode.EventEmitter(); @@ -43,6 +44,10 @@ export class GitHubAuthenticationProvider { context.subscriptions.push(context.secrets.onDidChange(() => this.checkForUpdates())); } + async getSessions(scopes: string[]): Promise { + return this._sessions.filter(session => arrayEquals(session.scopes, scopes)); + } + private async verifySessions(): Promise { const verifiedSessions: vscode.AuthenticationSession[] = []; const verificationPromises = this._sessions.map(async session => { diff --git a/extensions/microsoft-authentication/src/AADHelper.ts b/extensions/microsoft-authentication/src/AADHelper.ts index c36b49cb8d0..17ff85a6db9 100644 --- a/extensions/microsoft-authentication/src/AADHelper.ts +++ b/extensions/microsoft-authentication/src/AADHelper.ts @@ -300,6 +300,12 @@ export class AzureActiveDirectoryService { return Promise.all(this._tokens.map(token => this.convertToSession(token))); } + async getSessions(scopes: string[]): Promise { + const orderedScopes = scopes.sort().join(' '); + const matchingTokens = this._tokens.filter(token => token.scope === orderedScopes); + return Promise.all(this._tokens.map(token => this.convertToSession(token))); + } + public async login(scope: string): Promise { Logger.info('Logging in...'); if (!scope.includes('offline_access')) { diff --git a/extensions/microsoft-authentication/src/extension.ts b/extensions/microsoft-authentication/src/extension.ts index dbf93db8bda..f949ec1ec2d 100644 --- a/extensions/microsoft-authentication/src/extension.ts +++ b/extensions/microsoft-authentication/src/extension.ts @@ -20,7 +20,8 @@ export async function activate(context: vscode.ExtensionContext) { context.subscriptions.push(vscode.authentication.registerAuthenticationProvider('microsoft', 'Microsoft', { onDidChangeSessions: onDidChangeSessions.event, - getSessions: () => Promise.resolve(loginService.sessions), + getAllSessions: () => Promise.resolve(loginService.sessions), + getSessions: (scopes: string[]) => loginService.getSessions(scopes), login: async (scopes: string[]) => { try { /* __GDPR__ diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index f4e93782bff..8cd964987cb 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -65,9 +65,18 @@ declare module 'vscode' { /** * Returns an array of current sessions. + * + * TODO @RMacfarlane finish deprecating this and remove it */ // eslint-disable-next-line vscode-dts-provider-naming - getSessions(): Thenable>; + getAllSessions(): Thenable>; + + + /** + * Returns an array of current sessions. + */ + // eslint-disable-next-line vscode-dts-provider-naming + getSessions(scopes: string[]): Thenable>; /** * Prompts a user to login. diff --git a/src/vs/workbench/api/browser/mainThreadAuthentication.ts b/src/vs/workbench/api/browser/mainThreadAuthentication.ts index fe87eb11f64..c7004edd94c 100644 --- a/src/vs/workbench/api/browser/mainThreadAuthentication.ts +++ b/src/vs/workbench/api/browser/mainThreadAuthentication.ts @@ -19,7 +19,6 @@ import { ActivationKind, IExtensionService } from 'vs/workbench/services/extensi export class MainThreadAuthenticationProvider extends Disposable { private _accounts = new Map(); // Map account name to session ids - private _sessions = new Map(); // Map account id to name private _hasInitializedSessions = false; @@ -35,10 +34,6 @@ export class MainThreadAuthenticationProvider extends Disposable { ) { super(); } - public hasSessions(): boolean { - return !!this._sessions.size; - } - public manageTrustedExtensions(accountName: string) { const allowedExtensions = readAllowedExtensions(this.storageService, this.id, accountName); @@ -81,8 +76,6 @@ export class MainThreadAuthenticationProvider extends Disposable { } private registerSession(session: modes.AuthenticationSession) { - this._sessions.set(session.id, session.account.label); - const existingSessionsForAccount = this._accounts.get(session.account.label); if (existingSessionsForAccount) { this._accounts.set(session.account.label, existingSessionsForAccount.concat(session.id)); @@ -110,8 +103,12 @@ export class MainThreadAuthenticationProvider extends Disposable { } } - async getSessions(): Promise> { - const sessions = await this._proxy.$getSessions(this.id); + async getSessions(scopes: string[]) { + return this._proxy.$getSessions(this.id, scopes); + } + + async getAllSessions(): Promise> { + const sessions = await this._proxy.$getAllSessions(this.id); if (!this._hasInitializedSessions) { sessions.forEach(session => this.registerSession(session)); this._hasInitializedSessions = true; @@ -125,12 +122,11 @@ export class MainThreadAuthenticationProvider extends Disposable { removed.forEach(session => { const sessionId = session.id; - const accountName = this._sessions.get(sessionId); + const accountName = session.account.label; if (accountName) { - this._sessions.delete(sessionId); let sessionsForAccount = this._accounts.get(accountName) || []; const sessionIndex = sessionsForAccount.indexOf(sessionId); - sessionsForAccount.splice(sessionIndex); + sessionsForAccount.splice(sessionIndex, 1); if (!sessionsForAccount.length) { this._accounts.delete(accountName); @@ -230,7 +226,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu } - private async selectSession(providerId: string, extensionId: string, extensionName: string, potentialSessions: modes.AuthenticationSession[], clearSessionPreference: boolean): Promise { + private async selectSession(providerId: string, extensionId: string, extensionName: string, potentialSessions: readonly modes.AuthenticationSession[], clearSessionPreference: boolean): Promise { if (!potentialSessions.length) { throw new Error('No potential sessions found'); } @@ -259,8 +255,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu } async $getSession(providerId: string, scopes: string[], extensionId: string, extensionName: string, options: { createIfNone: boolean, clearSessionPreference: boolean }): Promise { - const orderedScopes = scopes.sort().join(' '); - const sessions = (await this.authenticationService.getSessions(providerId, true)).filter(session => session.scopes.slice().sort().join(' ') === orderedScopes); + const sessions = await this.authenticationService.getSessions(providerId, scopes, true); const silent = !options.createIfNone; let session: modes.AuthenticationSession | undefined; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 431c76b1616..37ed3830c68 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1126,8 +1126,8 @@ export interface ExtHostLabelServiceShape { } export interface ExtHostAuthenticationShape { - $getSessions(id: string): Promise>; - $getSessionAccessToken(id: string, sessionId: string): Promise; + $getAllSessions(id: string): Promise>; + $getSessions(id: string, scopes: string[]): Promise>; $login(id: string, scopes: string[]): Promise; $logout(id: string, sessionId: string): Promise; $onDidChangeAuthenticationSessions(id: string, label: string, event: modes.AuthenticationSessionsChangeEvent): Promise; diff --git a/src/vs/workbench/api/common/extHostAuthentication.ts b/src/vs/workbench/api/common/extHostAuthentication.ts index 5a3aab45657..8a170d227ac 100644 --- a/src/vs/workbench/api/common/extHostAuthentication.ts +++ b/src/vs/workbench/api/common/extHostAuthentication.ts @@ -147,25 +147,19 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape { throw new Error(`Unable to find authentication provider with handle: ${providerId}`); } - $getSessions(providerId: string): Promise> { + $getAllSessions(providerId: string): Promise> { const providerData = this._authenticationProviders.get(providerId); if (providerData) { - return Promise.resolve(providerData.provider.getSessions()); + return Promise.resolve(providerData.provider.getAllSessions()); } throw new Error(`Unable to find authentication provider with handle: ${providerId}`); } - async $getSessionAccessToken(providerId: string, sessionId: string): Promise { + $getSessions(providerId: string, scopes: string[]): Promise> { const providerData = this._authenticationProviders.get(providerId); if (providerData) { - const sessions = await providerData.provider.getSessions(); - const session = sessions.find(session => session.id === sessionId); - if (session) { - return session.accessToken; - } - - throw new Error(`Unable to find session with id: ${sessionId}`); + return Promise.resolve(providerData.provider.getSessions(scopes)); } throw new Error(`Unable to find authentication provider with handle: ${providerId}`); diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index e9f0df8d2e0..310f2f7c211 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -210,7 +210,7 @@ export class AccountsActivityActionViewItem extends MenuActivityActionViewItem { const providers = this.authenticationService.getProviderIds(); const allSessions = providers.map(async providerId => { try { - const sessions = await this.authenticationService.getSessions(providerId); + const sessions = await this.authenticationService.getAllSessions(providerId); const groupedSessions: { [label: string]: AuthenticationSession[]; } = {}; sessions.forEach(session => { diff --git a/src/vs/workbench/contrib/issue/electron-sandbox/issueService.ts b/src/vs/workbench/contrib/issue/electron-sandbox/issueService.ts index 94beb1646ae..1deb2d639b0 100644 --- a/src/vs/workbench/contrib/issue/electron-sandbox/issueService.ts +++ b/src/vs/workbench/contrib/issue/electron-sandbox/issueService.ts @@ -54,7 +54,7 @@ export class WorkbenchIssueService implements IWorkbenchIssueService { }; }); const experiments = await this.experimentService.getCurrentExperiments(); - const githubSessions = await this.authenticationService.getSessions('github'); + const githubSessions = await this.authenticationService.getAllSessions('github'); const potentialSessions = githubSessions.filter(session => session.scopes.includes('repo')); const theme = this.themeService.getColorTheme(); const issueReporterData: IssueReporterData = Object.assign({ diff --git a/src/vs/workbench/contrib/url/browser/trustedDomains.ts b/src/vs/workbench/contrib/url/browser/trustedDomains.ts index 145afdf032c..b5188bfb036 100644 --- a/src/vs/workbench/contrib/url/browser/trustedDomains.ts +++ b/src/vs/workbench/contrib/url/browser/trustedDomains.ts @@ -206,7 +206,7 @@ export async function readWorkspaceTrustedDomains(accessor: ServicesAccessor): P export async function readAuthenticationTrustedDomains(accessor: ServicesAccessor): Promise { const authenticationService = accessor.get(IAuthenticationService); - return authenticationService.isAuthenticationProviderRegistered('github') && ((await authenticationService.getSessions('github')) ?? []).length > 0 + return authenticationService.isAuthenticationProviderRegistered('github') && ((await authenticationService.getAllSessions('github')) ?? []).length > 0 ? [`https://github.com`] : []; } diff --git a/src/vs/workbench/services/authentication/browser/authenticationService.ts b/src/vs/workbench/services/authentication/browser/authenticationService.ts index 69df3cd2cdc..a97706d780c 100644 --- a/src/vs/workbench/services/authentication/browser/authenticationService.ts +++ b/src/vs/workbench/services/authentication/browser/authenticationService.ts @@ -110,8 +110,8 @@ export interface IAuthenticationService { unregisterAuthenticationProvider(id: string): void; isAccessAllowed(providerId: string, accountName: string, extensionId: string): boolean; showGetSessionPrompt(providerId: string, accountName: string, extensionId: string, extensionName: string): Promise; - selectSession(providerId: string, extensionId: string, extensionName: string, possibleSessions: AuthenticationSession[]): Promise; - requestSessionAccess(providerId: string, extensionId: string, extensionName: string, possibleSessions: AuthenticationSession[]): void; + selectSession(providerId: string, extensionId: string, extensionName: string, possibleSessions: readonly AuthenticationSession[]): Promise; + requestSessionAccess(providerId: string, extensionId: string, extensionName: string, possibleSessions: readonly AuthenticationSession[]): void; completeSessionAccessRequest(providerId: string, extensionId: string, extensionName: string): Promise requestNewSession(providerId: string, scopes: string[], extensionId: string, extensionName: string): Promise; sessionsUpdate(providerId: string, event: AuthenticationSessionsChangeEvent): void; @@ -124,7 +124,8 @@ export interface IAuthenticationService { declaredProviders: AuthenticationProviderInformation[]; readonly onDidChangeDeclaredProviders: Event; - getSessions(providerId: string, activateImmediate?: boolean): Promise>; + getSessions(id: string, scopes: string[], activateImmediate?: boolean): Promise>; + getAllSessions(providerId: string, activateImmediate?: boolean): Promise>; getLabel(providerId: string): string; supportsMultipleAccounts(providerId: string): boolean; login(providerId: string, scopes: string[], activateImmediate?: boolean): Promise; @@ -694,10 +695,19 @@ export class AuthenticationService extends Disposable implements IAuthentication return Promise.race([didRegister, didTimeout]); } - async getSessions(id: string, activateImmediate: boolean = false): Promise> { + async getAllSessions(id: string, activateImmediate: boolean = false): Promise> { try { const authProvider = this._authenticationProviders.get(id) || await this.tryActivateProvider(id, activateImmediate); - return await authProvider.getSessions(); + return await authProvider.getAllSessions(); + } catch (_) { + throw new Error(`No authentication provider '${id}' is currently registered.`); + } + } + + async getSessions(id: string, scopes: string[], activateImmediate: boolean = false): Promise> { + try { + const authProvider = this._authenticationProviders.get(id) || await this.tryActivateProvider(id, activateImmediate); + return await authProvider.getSessions(scopes); } catch (_) { throw new Error(`No authentication provider '${id}' is currently registered.`); } diff --git a/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts b/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts index b066db65e06..ec7bc09735a 100644 --- a/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts +++ b/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts @@ -202,7 +202,7 @@ export class UserDataSyncWorkbenchService extends Disposable implements IUserDat let accounts: Map = new Map(); let currentAccount: UserDataSyncAccount | null = null; - const sessions = await this.authenticationService.getSessions(authenticationProviderId) || []; + const sessions = await this.authenticationService.getAllSessions(authenticationProviderId) || []; for (const session of sessions) { const account: UserDataSyncAccount = new UserDataSyncAccount(authenticationProviderId, session); accounts.set(account.accountName, account); From e4cf7f46ee2f2678707f373d627959c2973244b9 Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Thu, 11 Feb 2021 13:39:38 -0800 Subject: [PATCH 030/325] Remove account caching from MainThreadAuthenticationProvider --- .../api/browser/mainThreadAuthentication.ts | 48 ++----------------- .../parts/activitybar/activitybarActions.ts | 2 +- .../browser/authenticationService.ts | 7 ++- 3 files changed, 8 insertions(+), 49 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadAuthentication.ts b/src/vs/workbench/api/browser/mainThreadAuthentication.ts index c7004edd94c..c0e48209936 100644 --- a/src/vs/workbench/api/browser/mainThreadAuthentication.ts +++ b/src/vs/workbench/api/browser/mainThreadAuthentication.ts @@ -18,10 +18,6 @@ import { fromNow } from 'vs/base/common/date'; import { ActivationKind, IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; export class MainThreadAuthenticationProvider extends Disposable { - private _accounts = new Map(); // Map account name to session ids - - private _hasInitializedSessions = false; - constructor( private readonly _proxy: ExtHostAuthenticationShape, public readonly id: string, @@ -75,19 +71,8 @@ export class MainThreadAuthenticationProvider extends Disposable { quickPick.show(); } - private registerSession(session: modes.AuthenticationSession) { - const existingSessionsForAccount = this._accounts.get(session.account.label); - if (existingSessionsForAccount) { - this._accounts.set(session.account.label, existingSessionsForAccount.concat(session.id)); - return; - } else { - this._accounts.set(session.account.label, [session.id]); - } - } - - async signOut(accountName: string): Promise { + async signOut(accountName: string, sessions: modes.AuthenticationSession[]): Promise { const accountUsages = readAccountUsages(this.storageService, this.id, accountName); - const sessionsForAccount = this._accounts.get(accountName); const result = await this.dialogService.confirm({ title: nls.localize('signOutConfirm', "Sign out of {0}", accountName), @@ -97,7 +82,8 @@ export class MainThreadAuthenticationProvider extends Disposable { }); if (result.confirmed) { - sessionsForAccount?.forEach(sessionId => this.logout(sessionId)); + const logoutPromises = sessions.map(session => this.logout(session.id)); + await Promise.all(logoutPromises); removeAccountUsage(this.storageService, this.id, accountName); this.storageService.remove(`${this.id}-${accountName}`, StorageScope.GLOBAL); } @@ -108,33 +94,7 @@ export class MainThreadAuthenticationProvider extends Disposable { } async getAllSessions(): Promise> { - const sessions = await this._proxy.$getAllSessions(this.id); - if (!this._hasInitializedSessions) { - sessions.forEach(session => this.registerSession(session)); - this._hasInitializedSessions = true; - } - - return sessions; - } - - async updateSessionItems(event: modes.AuthenticationSessionsChangeEvent): Promise { - const { added, removed } = event; - - removed.forEach(session => { - const sessionId = session.id; - const accountName = session.account.label; - if (accountName) { - let sessionsForAccount = this._accounts.get(accountName) || []; - const sessionIndex = sessionsForAccount.indexOf(sessionId); - sessionsForAccount.splice(sessionIndex, 1); - - if (!sessionsForAccount.length) { - this._accounts.delete(accountName); - } - } - }); - - added.forEach(session => this.registerSession(session)); + return this._proxy.$getAllSessions(this.id); } login(scopes: string[]): Promise { diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 310f2f7c211..f443898f7b2 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -240,7 +240,7 @@ export class AccountsActivityActionViewItem extends MenuActivityActionViewItem { })); const signOutAction = disposables.add(new Action('signOut', localize('signOut', "Sign Out"), '', true, () => { - return this.authenticationService.signOutOfAccount(sessionInfo.providerId, accountName); + return this.authenticationService.signOutOfAccount(sessionInfo.providerId, accountName, sessionInfo.sessions[accountName]); })); const providerSubMenuActions = [manageExtensionsAction]; diff --git a/src/vs/workbench/services/authentication/browser/authenticationService.ts b/src/vs/workbench/services/authentication/browser/authenticationService.ts index a97706d780c..ec4005a5e78 100644 --- a/src/vs/workbench/services/authentication/browser/authenticationService.ts +++ b/src/vs/workbench/services/authentication/browser/authenticationService.ts @@ -132,7 +132,7 @@ export interface IAuthenticationService { logout(providerId: string, sessionId: string): Promise; manageTrustedExtensionsForAccount(providerId: string, accountName: string): Promise; - signOutOfAccount(providerId: string, accountName: string): Promise; + signOutOfAccount(providerId: string, accountName: string, sessions: AuthenticationSession[]): Promise; } export interface AllowedExtension { @@ -316,7 +316,6 @@ export class AuthenticationService extends Disposable implements IAuthentication const provider = this._authenticationProviders.get(id); if (provider) { this._onDidChangeSessions.fire({ providerId: id, label: provider.label, event: event }); - await provider.updateSessionItems(event); if (event.added) { await this.updateNewSessionRequests(provider, event.added); @@ -740,10 +739,10 @@ export class AuthenticationService extends Disposable implements IAuthentication } } - async signOutOfAccount(id: string, accountName: string): Promise { + async signOutOfAccount(id: string, accountName: string, sessions: AuthenticationSession[]): Promise { const authProvider = this._authenticationProviders.get(id); if (authProvider) { - return authProvider.signOut(accountName); + return authProvider.signOut(accountName, sessions); } else { throw new Error(`No authentication provider '${id}' is currently registered.`); } From 2dea6ff4bbc11865d979340f19b96b33bac19614 Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Thu, 11 Feb 2021 14:59:44 -0800 Subject: [PATCH 031/325] fixes #116142 --- src/vs/workbench/browser/actions/layoutActions.ts | 2 +- src/vs/workbench/browser/layout.ts | 6 ++---- .../workbench/browser/parts/activitybar/activitybarPart.ts | 6 +++--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/browser/actions/layoutActions.ts b/src/vs/workbench/browser/actions/layoutActions.ts index 7220bc5c04f..9bb28af606c 100644 --- a/src/vs/workbench/browser/actions/layoutActions.ts +++ b/src/vs/workbench/browser/actions/layoutActions.ts @@ -462,7 +462,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { command: { id: ToggleMenuBarAction.ID, title: nls.localize({ key: 'miShowMenuBar', comment: ['&& denotes a mnemonic'] }, "Show Menu &&Bar"), - toggled: ContextKeyExpr.and(IsMacNativeContext.toNegated(), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'hidden'), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'toggle')) + toggled: ContextKeyExpr.and(IsMacNativeContext.toNegated(), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'hidden'), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'toggle'), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'compact')) }, when: IsMacNativeContext.toNegated(), order: 0 diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 1399e64b7d5..aee8f415442 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -1586,11 +1586,9 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi let newVisibilityValue: string; if (currentVisibilityValue === 'visible' || currentVisibilityValue === 'classic') { - newVisibilityValue = 'toggle'; - } else if (currentVisibilityValue === 'compact') { - newVisibilityValue = 'hidden'; + newVisibilityValue = 'compact'; } else { - newVisibilityValue = (isWeb && currentVisibilityValue === 'hidden') ? 'compact' : 'classic'; + newVisibilityValue = 'classic'; } this.configurationService.updateValue(Storage.MENU_VISIBILITY, newVisibilityValue); diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index b0908cbc3e2..ba37e0b668f 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -32,7 +32,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { CustomMenubarControl } from 'vs/workbench/browser/parts/titlebar/menubarControl'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { getMenuBarVisibility } from 'vs/platform/windows/common/windows'; -import { isNative, isWeb } from 'vs/base/common/platform'; +import { isNative } from 'vs/base/common/platform'; import { Before2D } from 'vs/workbench/browser/dnd'; import { Codicon } from 'vs/base/common/codicons'; import { IAction, Separator, toAction } from 'vs/base/common/actions'; @@ -166,7 +166,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { // Menu const menuBarVisibility = getMenuBarVisibility(this.configurationService); - if (menuBarVisibility === 'compact' || (menuBarVisibility === 'hidden' && isWeb)) { + if (menuBarVisibility === 'compact' || menuBarVisibility === 'hidden' || menuBarVisibility === 'toggle') { topActions.push({ id: 'toggleMenuVisibility', label: localize('menu', "Menu"), @@ -174,7 +174,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { tooltip: localize('menu', "Menu"), checked: menuBarVisibility === 'compact', enabled: true, - run: async () => this.layoutService.toggleMenuBar(), + run: async () => this.configurationService.updateValue('window.menuBarVisibility', menuBarVisibility === 'compact' ? 'toggle' : 'compact'), dispose: () => { } }); } From 98354ad7cc5359879ba92590124fe165396e3881 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 11 Feb 2021 15:50:09 -0800 Subject: [PATCH 032/325] Add comment about localization string Fixes #115781 --- src/vs/workbench/api/browser/mainThreadUriOpeners.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/api/browser/mainThreadUriOpeners.ts b/src/vs/workbench/api/browser/mainThreadUriOpeners.ts index 200d4ae4dc0..96eb6fd8698 100644 --- a/src/vs/workbench/api/browser/mainThreadUriOpeners.ts +++ b/src/vs/workbench/api/browser/mainThreadUriOpeners.ts @@ -87,7 +87,10 @@ export class MainThreadUriOpeners extends Disposable implements MainThreadUriOpe this.notificationService.notify({ severity: Severity.Error, - message: localize('openerFailedMessage', 'Could not open uri with \'{0}\': {1}', id, e.toString()), + message: localize({ + key: 'openerFailedMessage', + comment: ['{0} is the id of the opener. {1} is the url being opened.'], + }, 'Could not open uri with \'{0}\': {1}', id, e.toString()), actions: { primary: [ openDefaultAction From ea865096f131b5369c36bc06ed2c1979879fa497 Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Thu, 11 Feb 2021 16:15:28 -0800 Subject: [PATCH 033/325] allow for tiered trust (walk the tree) --- .../workspaces/common/workspaceTrust.ts | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/services/workspaces/common/workspaceTrust.ts b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts index daff0ecda29..f8ea335eae8 100644 --- a/src/vs/workbench/services/workspaces/common/workspaceTrust.ts +++ b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts @@ -12,6 +12,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { IWorkspace, IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceTrustModel, IWorkspaceTrustRequest, IWorkspaceTrustRequestModel, IWorkspaceTrustService, IWorkspaceTrustStateInfo, WorkspaceTrustState, WorkspaceTrustStateChangeEvent } from 'vs/platform/workspace/common/workspaceTrust'; +import { isEqual, isEqualOrParent } from 'vs/base/common/extpath'; export const WORKSPACE_TRUST_ENABLED = 'workspace.trustEnabled'; export const WORKSPACE_TRUST_STORAGE_KEY = 'content.trust.model.key'; @@ -84,9 +85,11 @@ export class WorkspaceTrustModel extends Disposable implements IWorkspaceTrustMo setFolderTrustState(folder: URI, trustState: WorkspaceTrustState): void { let changed = false; + const folderPath = folder.fsPath; + if (trustState === WorkspaceTrustState.Unknown) { const before = this.trustStateInfo.localFolders.length; - this.trustStateInfo.localFolders = this.trustStateInfo.localFolders.filter(info => info.uri !== folder.toString()); + this.trustStateInfo.localFolders = this.trustStateInfo.localFolders.filter(info => isEqual(URI.file(info.uri).fsPath, folderPath)); if (this.trustStateInfo.localFolders.length !== before) { changed = true; @@ -94,7 +97,7 @@ export class WorkspaceTrustModel extends Disposable implements IWorkspaceTrustMo } else { let found = false; for (const trustInfo of this.trustStateInfo.localFolders) { - if (trustInfo.uri === folder.toString()) { + if (isEqual(URI.file(trustInfo.uri).fsPath, folderPath)) { found = true; if (trustInfo.trustState !== trustState) { trustInfo.trustState = trustState; @@ -104,7 +107,7 @@ export class WorkspaceTrustModel extends Disposable implements IWorkspaceTrustMo } if (!found) { - this.trustStateInfo.localFolders.push({ uri: folder.toString(), trustState }); + this.trustStateInfo.localFolders.push({ uri: folderPath, trustState }); changed = true; } } @@ -115,13 +118,22 @@ export class WorkspaceTrustModel extends Disposable implements IWorkspaceTrustMo } getFolderTrustState(folder: URI): WorkspaceTrustState { + let result = WorkspaceTrustState.Unknown; + let maxLength = -1; + + const folderPath = folder.fsPath; for (const trustInfo of this.trustStateInfo.localFolders) { - if (trustInfo.uri === folder.toString()) { - return trustInfo.trustState; + const trustInfoPath = URI.file(trustInfo.uri).fsPath; + + if (isEqualOrParent(folderPath, trustInfoPath)) { + if (trustInfoPath.length > maxLength) { + maxLength = trustInfoPath.length; + result = trustInfo.trustState; + } } } - return WorkspaceTrustState.Unknown; + return result; } } From eceff53351511e75b3c87f1600cebdd7f2df0737 Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Thu, 11 Feb 2021 16:44:35 -0800 Subject: [PATCH 034/325] Rename login/logout to createSession/removeSession --- .../github-authentication/src/extension.ts | 8 +++---- .../github-authentication/src/github.ts | 4 ++-- .../microsoft-authentication/src/AADHelper.ts | 12 +++++----- .../microsoft-authentication/src/extension.ts | 8 +++---- src/vs/vscode.proposed.d.ts | 4 ++-- .../api/browser/mainThreadAuthentication.ts | 20 ++++++++--------- .../workbench/api/common/extHost.api.impl.ts | 2 +- .../workbench/api/common/extHost.protocol.ts | 6 ++--- .../api/common/extHostAuthentication.ts | 14 ++++++------ .../parts/activitybar/activitybarActions.ts | 2 +- .../browser/authenticationService.ts | 22 +++++++++---------- .../browser/userDataSyncWorkbenchService.ts | 2 +- 12 files changed, 52 insertions(+), 52 deletions(-) diff --git a/extensions/github-authentication/src/extension.ts b/extensions/github-authentication/src/extension.ts index bd41ea45535..c9b76d81670 100644 --- a/extensions/github-authentication/src/extension.ts +++ b/extensions/github-authentication/src/extension.ts @@ -26,14 +26,14 @@ export async function activate(context: vscode.ExtensionContext) { onDidChangeSessions: onDidChangeSessions.event, getAllSessions: () => Promise.resolve(loginService.sessions), getSessions: (scopes: string[]) => loginService.getSessions(scopes), - login: async (scopeList: string[]) => { + createSession: async (scopeList: string[]) => { try { /* __GDPR__ "login" : { } */ telemetryReporter.sendTelemetryEvent('login'); - const session = await loginService.login(scopeList.sort().join(' ')); + const session = await loginService.createSession(scopeList.sort().join(' ')); Logger.info('Login success!'); onDidChangeSessions.fire({ added: [session], removed: [], changed: [] }); return session; @@ -57,14 +57,14 @@ export async function activate(context: vscode.ExtensionContext) { throw e; } }, - logout: async (id: string) => { + removeSession: async (id: string) => { try { /* __GDPR__ "logout" : { } */ telemetryReporter.sendTelemetryEvent('logout'); - const session = await loginService.logout(id); + const session = await loginService.removeSession(id); if (session) { onDidChangeSessions.fire({ added: [], removed: [session], changed: [] }); } diff --git a/extensions/github-authentication/src/github.ts b/extensions/github-authentication/src/github.ts index f3ef508cd5c..89893c94ccd 100644 --- a/extensions/github-authentication/src/github.ts +++ b/extensions/github-authentication/src/github.ts @@ -158,7 +158,7 @@ export class GitHubAuthenticationProvider { return this._sessions; } - public async login(scopes: string): Promise { + public async createSession(scopes: string): Promise { const token = await this._githubServer.login(scopes); const session = await this.tokenToSession(token, scopes.split(' ')); await this.setToken(session); @@ -190,7 +190,7 @@ export class GitHubAuthenticationProvider { await this.storeSessions(); } - public async logout(id: string): Promise { + public async removeSession(id: string): Promise { Logger.info(`Logging out of ${id}`); const sessionIndex = this._sessions.findIndex(session => session.id === id); let session: vscode.AuthenticationSession | undefined; diff --git a/extensions/microsoft-authentication/src/AADHelper.ts b/extensions/microsoft-authentication/src/AADHelper.ts index 17ff85a6db9..cd8b66075fc 100644 --- a/extensions/microsoft-authentication/src/AADHelper.ts +++ b/extensions/microsoft-authentication/src/AADHelper.ts @@ -144,7 +144,7 @@ export class AzureActiveDirectoryService { this.pollForReconnect(session.id, session.refreshToken, session.scope); } } else { - await this.logout(session.id); + await this.removeSession(session.id); } } }); @@ -193,7 +193,7 @@ export class AzureActiveDirectoryService { if (e.message === REFRESH_NETWORK_FAILURE) { // Ignore, will automatically retry on next poll. } else { - await this.logout(session.id); + await this.removeSession(session.id); } } } @@ -202,7 +202,7 @@ export class AzureActiveDirectoryService { promises = promises.concat(this._tokens.map(async token => { const matchesExisting = sessions.some(session => token.scope === session.scope && token.sessionId === session.id); if (!matchesExisting) { - await this.logout(token.sessionId); + await this.removeSession(token.sessionId); removed.push(this.convertToSessionSync(token)); } })); @@ -306,7 +306,7 @@ export class AzureActiveDirectoryService { return Promise.all(this._tokens.map(token => this.convertToSession(token))); } - public async login(scope: string): Promise { + public async createSession(scope: string): Promise { Logger.info('Logging in...'); if (!scope.includes('offline_access')) { Logger.info('Warning: The \'offline_access\' scope was not included, so the generated token will not be able to be refreshed.'); @@ -507,7 +507,7 @@ export class AzureActiveDirectoryService { this.pollForReconnect(token.sessionId, token.refreshToken, token.scope); } } else { - await this.logout(token.sessionId); + await this.removeSession(token.sessionId); onDidChangeSessions.fire({ added: [], removed: [this.convertToSessionSync(token)], changed: [] }); } } @@ -687,7 +687,7 @@ export class AzureActiveDirectoryService { }); } - public async logout(sessionId: string): Promise { + public async removeSession(sessionId: string): Promise { Logger.info(`Logging out of session '${sessionId}'`); const token = this.removeInMemorySessionData(sessionId); let session: vscode.AuthenticationSession | undefined; diff --git a/extensions/microsoft-authentication/src/extension.ts b/extensions/microsoft-authentication/src/extension.ts index f949ec1ec2d..584a4027b64 100644 --- a/extensions/microsoft-authentication/src/extension.ts +++ b/extensions/microsoft-authentication/src/extension.ts @@ -22,14 +22,14 @@ export async function activate(context: vscode.ExtensionContext) { onDidChangeSessions: onDidChangeSessions.event, getAllSessions: () => Promise.resolve(loginService.sessions), getSessions: (scopes: string[]) => loginService.getSessions(scopes), - login: async (scopes: string[]) => { + createSession: async (scopes: string[]) => { try { /* __GDPR__ "login" : { } */ telemetryReporter.sendTelemetryEvent('login'); - const session = await loginService.login(scopes.sort().join(' ')); + const session = await loginService.createSession(scopes.sort().join(' ')); onDidChangeSessions.fire({ added: [session], removed: [], changed: [] }); return session; } catch (e) { @@ -41,14 +41,14 @@ export async function activate(context: vscode.ExtensionContext) { throw e; } }, - logout: async (id: string) => { + removeSession: async (id: string) => { try { /* __GDPR__ "logout" : { } */ telemetryReporter.sendTelemetryEvent('logout'); - const session = await loginService.logout(id); + const session = await loginService.removeSession(id); if (session) { onDidChangeSessions.fire({ added: [], removed: [session], changed: [] }); } diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 8cd964987cb..9cf63216b00 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -82,14 +82,14 @@ declare module 'vscode' { * Prompts a user to login. */ // eslint-disable-next-line vscode-dts-provider-naming - login(scopes: string[]): Thenable; + createSession(scopes: string[]): Thenable; /** * Removes the session corresponding to session id. * @param sessionId The session id to log out of */ // eslint-disable-next-line vscode-dts-provider-naming - logout(sessionId: string): Thenable; + removeSession(sessionId: string): Thenable; } /** diff --git a/src/vs/workbench/api/browser/mainThreadAuthentication.ts b/src/vs/workbench/api/browser/mainThreadAuthentication.ts index c0e48209936..dfad0388642 100644 --- a/src/vs/workbench/api/browser/mainThreadAuthentication.ts +++ b/src/vs/workbench/api/browser/mainThreadAuthentication.ts @@ -71,7 +71,7 @@ export class MainThreadAuthenticationProvider extends Disposable { quickPick.show(); } - async signOut(accountName: string, sessions: modes.AuthenticationSession[]): Promise { + async removeAccountSessions(accountName: string, sessions: modes.AuthenticationSession[]): Promise { const accountUsages = readAccountUsages(this.storageService, this.id, accountName); const result = await this.dialogService.confirm({ @@ -82,8 +82,8 @@ export class MainThreadAuthenticationProvider extends Disposable { }); if (result.confirmed) { - const logoutPromises = sessions.map(session => this.logout(session.id)); - await Promise.all(logoutPromises); + const removeSessionPromises = sessions.map(session => this.removeSession(session.id)); + await Promise.all(removeSessionPromises); removeAccountUsage(this.storageService, this.id, accountName); this.storageService.remove(`${this.id}-${accountName}`, StorageScope.GLOBAL); } @@ -97,12 +97,12 @@ export class MainThreadAuthenticationProvider extends Disposable { return this._proxy.$getAllSessions(this.id); } - login(scopes: string[]): Promise { - return this._proxy.$login(this.id, scopes); + createSession(scopes: string[]): Promise { + return this._proxy.$createSession(this.id, scopes); } - async logout(sessionId: string): Promise { - await this._proxy.$logout(this.id, sessionId); + async removeSession(sessionId: string): Promise { + await this._proxy.$removeSession(this.id, sessionId); this.notificationService.info(nls.localize('signedOut', "Successfully signed out.")); } } @@ -159,8 +159,8 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu this.authenticationService.sessionsUpdate(id, event); } - $logout(providerId: string, sessionId: string): Promise { - return this.authenticationService.logout(providerId, sessionId); + $removeSession(providerId: string, sessionId: string): Promise { + return this.authenticationService.removeSession(providerId, sessionId); } private async loginPrompt(providerName: string, extensionName: string): Promise { const { choice } = await this.dialogService.show( @@ -247,7 +247,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu throw new Error('User did not consent to login.'); } - session = await this.authenticationService.login(providerId, scopes, true); + session = await this.authenticationService.createSession(providerId, scopes, true); await this.setTrustedExtensionAndAccountPreference(providerId, session.account.label, extensionId, extensionName, session.id); } else { await this.authenticationService.requestNewSession(providerId, scopes, extensionId, extensionName); diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 865ded63659..51c3ad42cfa 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -230,7 +230,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I }, logout(providerId: string, sessionId: string): Thenable { checkProposedApiEnabled(extension); - return extHostAuthentication.logout(providerId, sessionId); + return extHostAuthentication.removeSession(providerId, sessionId); } }; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 37ed3830c68..47387b9d266 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -168,7 +168,7 @@ export interface MainThreadAuthenticationShape extends IDisposable { $ensureProvider(id: string): Promise; $sendDidChangeSessions(providerId: string, event: modes.AuthenticationSessionsChangeEvent): void; $getSession(providerId: string, scopes: string[], extensionId: string, extensionName: string, options: { createIfNone?: boolean, clearSessionPreference?: boolean }): Promise; - $logout(providerId: string, sessionId: string): Promise; + $removeSession(providerId: string, sessionId: string): Promise; } export interface MainThreadSecretStateShape extends IDisposable { @@ -1128,8 +1128,8 @@ export interface ExtHostLabelServiceShape { export interface ExtHostAuthenticationShape { $getAllSessions(id: string): Promise>; $getSessions(id: string, scopes: string[]): Promise>; - $login(id: string, scopes: string[]): Promise; - $logout(id: string, sessionId: string): Promise; + $createSession(id: string, scopes: string[]): Promise; + $removeSession(id: string, sessionId: string): Promise; $onDidChangeAuthenticationSessions(id: string, label: string, event: modes.AuthenticationSessionsChangeEvent): Promise; $onDidChangeAuthenticationProviders(added: modes.AuthenticationProviderInformation[], removed: modes.AuthenticationProviderInformation[]): Promise; $setProviders(providers: modes.AuthenticationProviderInformation[]): Promise; diff --git a/src/vs/workbench/api/common/extHostAuthentication.ts b/src/vs/workbench/api/common/extHostAuthentication.ts index 8a170d227ac..988f93a5c9f 100644 --- a/src/vs/workbench/api/common/extHostAuthentication.ts +++ b/src/vs/workbench/api/common/extHostAuthentication.ts @@ -87,13 +87,13 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape { return this._proxy.$getSession(providerId, scopes, extensionId, extensionName, options); } - async logout(providerId: string, sessionId: string): Promise { + async removeSession(providerId: string, sessionId: string): Promise { const providerData = this._authenticationProviders.get(providerId); if (!providerData) { - return this._proxy.$logout(providerId, sessionId); + return this._proxy.$removeSession(providerId, sessionId); } - return providerData.provider.logout(sessionId); + return providerData.provider.removeSession(sessionId); } registerAuthenticationProvider(id: string, label: string, provider: vscode.AuthenticationProvider, options?: vscode.AuthenticationProviderOptions): vscode.Disposable { @@ -129,19 +129,19 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape { }); } - $login(providerId: string, scopes: string[]): Promise { + $createSession(providerId: string, scopes: string[]): Promise { const providerData = this._authenticationProviders.get(providerId); if (providerData) { - return Promise.resolve(providerData.provider.login(scopes)); + return Promise.resolve(providerData.provider.createSession(scopes)); } throw new Error(`Unable to find authentication provider with handle: ${providerId}`); } - $logout(providerId: string, sessionId: string): Promise { + $removeSession(providerId: string, sessionId: string): Promise { const providerData = this._authenticationProviders.get(providerId); if (providerData) { - return Promise.resolve(providerData.provider.logout(sessionId)); + return Promise.resolve(providerData.provider.removeSession(sessionId)); } throw new Error(`Unable to find authentication provider with handle: ${providerId}`); diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index f443898f7b2..c3f7817a47f 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -240,7 +240,7 @@ export class AccountsActivityActionViewItem extends MenuActivityActionViewItem { })); const signOutAction = disposables.add(new Action('signOut', localize('signOut', "Sign Out"), '', true, () => { - return this.authenticationService.signOutOfAccount(sessionInfo.providerId, accountName, sessionInfo.sessions[accountName]); + return this.authenticationService.removeAccountSessions(sessionInfo.providerId, accountName, sessionInfo.sessions[accountName]); })); const providerSubMenuActions = [manageExtensionsAction]; diff --git a/src/vs/workbench/services/authentication/browser/authenticationService.ts b/src/vs/workbench/services/authentication/browser/authenticationService.ts index ec4005a5e78..5d6de318988 100644 --- a/src/vs/workbench/services/authentication/browser/authenticationService.ts +++ b/src/vs/workbench/services/authentication/browser/authenticationService.ts @@ -128,11 +128,11 @@ export interface IAuthenticationService { getAllSessions(providerId: string, activateImmediate?: boolean): Promise>; getLabel(providerId: string): string; supportsMultipleAccounts(providerId: string): boolean; - login(providerId: string, scopes: string[], activateImmediate?: boolean): Promise; - logout(providerId: string, sessionId: string): Promise; + createSession(providerId: string, scopes: string[], activateImmediate?: boolean): Promise; + removeSession(providerId: string, sessionId: string): Promise; manageTrustedExtensionsForAccount(providerId: string, accountName: string): Promise; - signOutOfAccount(providerId: string, accountName: string, sessions: AuthenticationSession[]): Promise; + removeAccountSessions(providerId: string, accountName: string, sessions: AuthenticationSession[]): Promise; } export interface AllowedExtension { @@ -473,7 +473,7 @@ export class AuthenticationService extends Disposable implements IAuthentication quickPick.placeholder = nls.localize('getSessionPlateholder', "Select an account for '{0}' to use or Esc to cancel", extensionName); quickPick.onDidAccept(async _ => { - const session = quickPick.selectedItems[0].session ?? await this.login(providerId, availableSessions[0].scopes as string[]); + const session = quickPick.selectedItems[0].session ?? await this.createSession(providerId, availableSessions[0].scopes as string[]); const accountName = session.account.label; const allowList = readAllowedExtensions(this.storageService, providerId, accountName); @@ -610,7 +610,7 @@ export class AuthenticationService extends Disposable implements IAuthentication handler: async (accessor) => { const authenticationService = accessor.get(IAuthenticationService); const storageService = accessor.get(IStorageService); - const session = await authenticationService.login(providerId, scopes); + const session = await authenticationService.createSession(providerId, scopes); // Add extension to allow list since user explicitly signed in on behalf of it const allowList = readAllowedExtensions(storageService, providerId, session.account.label); @@ -712,19 +712,19 @@ export class AuthenticationService extends Disposable implements IAuthentication } } - async login(id: string, scopes: string[], activateImmediate: boolean = false): Promise { + async createSession(id: string, scopes: string[], activateImmediate: boolean = false): Promise { try { const authProvider = this._authenticationProviders.get(id) || await this.tryActivateProvider(id, activateImmediate); - return await authProvider.login(scopes); + return await authProvider.createSession(scopes); } catch (_) { throw new Error(`No authentication provider '${id}' is currently registered.`); } } - async logout(id: string, sessionId: string): Promise { + async removeSession(id: string, sessionId: string): Promise { const authProvider = this._authenticationProviders.get(id); if (authProvider) { - return authProvider.logout(sessionId); + return authProvider.removeSession(sessionId); } else { throw new Error(`No authentication provider '${id}' is currently registered.`); } @@ -739,10 +739,10 @@ export class AuthenticationService extends Disposable implements IAuthentication } } - async signOutOfAccount(id: string, accountName: string, sessions: AuthenticationSession[]): Promise { + async removeAccountSessions(id: string, accountName: string, sessions: AuthenticationSession[]): Promise { const authProvider = this._authenticationProviders.get(id); if (authProvider) { - return authProvider.signOut(accountName, sessions); + return authProvider.removeAccountSessions(accountName, sessions); } else { throw new Error(`No authentication provider '${id}' is currently registered.`); } diff --git a/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts b/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts index ec7bc09735a..32228c4c3b0 100644 --- a/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts +++ b/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts @@ -471,7 +471,7 @@ export class UserDataSyncWorkbenchService extends Disposable implements IUserDat } let sessionId: string, accountName: string, accountId: string; if (isAuthenticationProvider(result)) { - const session = await this.authenticationService.login(result.id, result.scopes); + const session = await this.authenticationService.createSession(result.id, result.scopes); sessionId = session.id; accountName = session.account.label; accountId = session.account.id; From 263d4b75e2132a376dae1ab4f44092054bf49d76 Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Thu, 11 Feb 2021 16:46:32 -0800 Subject: [PATCH 035/325] Fix getSessions for microsoft auth provider --- extensions/microsoft-authentication/src/AADHelper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/microsoft-authentication/src/AADHelper.ts b/extensions/microsoft-authentication/src/AADHelper.ts index cd8b66075fc..fbb4e10a0e8 100644 --- a/extensions/microsoft-authentication/src/AADHelper.ts +++ b/extensions/microsoft-authentication/src/AADHelper.ts @@ -303,7 +303,7 @@ export class AzureActiveDirectoryService { async getSessions(scopes: string[]): Promise { const orderedScopes = scopes.sort().join(' '); const matchingTokens = this._tokens.filter(token => token.scope === orderedScopes); - return Promise.all(this._tokens.map(token => this.convertToSession(token))); + return Promise.all(matchingTokens.map(token => this.convertToSession(token))); } public async createSession(scope: string): Promise { From ba8a5d8fff8bda68715c2680321ce02b7b19c893 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Thu, 11 Feb 2021 14:58:36 -0800 Subject: [PATCH 036/325] [Deep clssifier] Lock dependencies --- .github/workflows/deep-classifier-runner.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deep-classifier-runner.yml b/.github/workflows/deep-classifier-runner.yml index 674b35d0b78..19a8a705971 100644 --- a/.github/workflows/deep-classifier-runner.yml +++ b/.github/workflows/deep-classifier-runner.yml @@ -38,7 +38,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install --upgrade numpy scipy scikit-learn joblib nltk simpletransformers torch torchvision + pip install --upgrade numpy==1.20.0 scipy==1.6.0 scikit-learn==0.24.1 joblib==1.0.0 nltk==3.5 simpletransformers==0.51.16 torch==1.7.1 torchvision==0.8.2 - name: "Run Classifier: Generator" run: python ./actions/classifier-deep/apply/generate-labels/main.py - name: "Run Classifier: Labeler" From 9b4f1aff5d25aae7122b2723b6b3f3f393e221c5 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 11 Feb 2021 16:03:56 -0800 Subject: [PATCH 037/325] Enable inline html tags in notebook markdown Fixes #113351 --- .../notebook-out/index.js | 965 +----------------- .../notebook/index.ts | 4 +- 2 files changed, 4 insertions(+), 965 deletions(-) diff --git a/extensions/markdown-language-features/notebook-out/index.js b/extensions/markdown-language-features/notebook-out/index.js index 00ad3efad5c..66df08f4026 100644 --- a/extensions/markdown-language-features/notebook-out/index.js +++ b/extensions/markdown-language-features/notebook-out/index.js @@ -1,964 +1 @@ -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); -/******/ } -/******/ }; -/******/ -/******/ // define __esModule on exports -/******/ __webpack_require__.r = function(exports) { -/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { -/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); -/******/ } -/******/ Object.defineProperty(exports, '__esModule', { value: true }); -/******/ }; -/******/ -/******/ // create a fake namespace object -/******/ // mode & 1: value is a module id, require it -/******/ // mode & 2: merge all properties of value into the ns -/******/ // mode & 4: return value when already ns object -/******/ // mode & 8|1: behave like require -/******/ __webpack_require__.t = function(value, mode) { -/******/ if(mode & 1) value = __webpack_require__(value); -/******/ if(mode & 8) return value; -/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; -/******/ var ns = Object.create(null); -/******/ __webpack_require__.r(ns); -/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); -/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); -/******/ return ns; -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = "./notebook/index.ts"); -/******/ }) -/************************************************************************/ -/******/ ({ - -/***/ "../../node_modules/punycode/punycode.js": -/*!*********************************************************************!*\ - !*** /Users/matb/projects/vscode/node_modules/punycode/punycode.js ***! - \*********************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -eval("/* WEBPACK VAR INJECTION */(function(module, global) {var __WEBPACK_AMD_DEFINE_RESULT__;/*! https://mths.be/punycode v1.4.1 by @mathias */\n;(function(root) {\n\n\t/** Detect free variables */\n\tvar freeExports = true && exports &&\n\t\t!exports.nodeType && exports;\n\tvar freeModule = true && module &&\n\t\t!module.nodeType && module;\n\tvar freeGlobal = typeof global == 'object' && global;\n\tif (\n\t\tfreeGlobal.global === freeGlobal ||\n\t\tfreeGlobal.window === freeGlobal ||\n\t\tfreeGlobal.self === freeGlobal\n\t) {\n\t\troot = freeGlobal;\n\t}\n\n\t/**\n\t * The `punycode` object.\n\t * @name punycode\n\t * @type Object\n\t */\n\tvar punycode,\n\n\t/** Highest positive signed 32-bit float value */\n\tmaxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1\n\n\t/** Bootstring parameters */\n\tbase = 36,\n\ttMin = 1,\n\ttMax = 26,\n\tskew = 38,\n\tdamp = 700,\n\tinitialBias = 72,\n\tinitialN = 128, // 0x80\n\tdelimiter = '-', // '\\x2D'\n\n\t/** Regular expressions */\n\tregexPunycode = /^xn--/,\n\tregexNonASCII = /[^\\x20-\\x7E]/, // unprintable ASCII chars + non-ASCII chars\n\tregexSeparators = /[\\x2E\\u3002\\uFF0E\\uFF61]/g, // RFC 3490 separators\n\n\t/** Error messages */\n\terrors = {\n\t\t'overflow': 'Overflow: input needs wider integers to process',\n\t\t'not-basic': 'Illegal input >= 0x80 (not a basic code point)',\n\t\t'invalid-input': 'Invalid input'\n\t},\n\n\t/** Convenience shortcuts */\n\tbaseMinusTMin = base - tMin,\n\tfloor = Math.floor,\n\tstringFromCharCode = String.fromCharCode,\n\n\t/** Temporary variable */\n\tkey;\n\n\t/*--------------------------------------------------------------------------*/\n\n\t/**\n\t * A generic error utility function.\n\t * @private\n\t * @param {String} type The error type.\n\t * @returns {Error} Throws a `RangeError` with the applicable error message.\n\t */\n\tfunction error(type) {\n\t\tthrow new RangeError(errors[type]);\n\t}\n\n\t/**\n\t * A generic `Array#map` utility function.\n\t * @private\n\t * @param {Array} array The array to iterate over.\n\t * @param {Function} callback The function that gets called for every array\n\t * item.\n\t * @returns {Array} A new array of values returned by the callback function.\n\t */\n\tfunction map(array, fn) {\n\t\tvar length = array.length;\n\t\tvar result = [];\n\t\twhile (length--) {\n\t\t\tresult[length] = fn(array[length]);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * A simple `Array#map`-like wrapper to work with domain name strings or email\n\t * addresses.\n\t * @private\n\t * @param {String} domain The domain name or email address.\n\t * @param {Function} callback The function that gets called for every\n\t * character.\n\t * @returns {Array} A new string of characters returned by the callback\n\t * function.\n\t */\n\tfunction mapDomain(string, fn) {\n\t\tvar parts = string.split('@');\n\t\tvar result = '';\n\t\tif (parts.length > 1) {\n\t\t\t// In email addresses, only the domain name should be punycoded. Leave\n\t\t\t// the local part (i.e. everything up to `@`) intact.\n\t\t\tresult = parts[0] + '@';\n\t\t\tstring = parts[1];\n\t\t}\n\t\t// Avoid `split(regex)` for IE8 compatibility. See #17.\n\t\tstring = string.replace(regexSeparators, '\\x2E');\n\t\tvar labels = string.split('.');\n\t\tvar encoded = map(labels, fn).join('.');\n\t\treturn result + encoded;\n\t}\n\n\t/**\n\t * Creates an array containing the numeric code points of each Unicode\n\t * character in the string. While JavaScript uses UCS-2 internally,\n\t * this function will convert a pair of surrogate halves (each of which\n\t * UCS-2 exposes as separate characters) into a single code point,\n\t * matching UTF-16.\n\t * @see `punycode.ucs2.encode`\n\t * @see \n\t * @memberOf punycode.ucs2\n\t * @name decode\n\t * @param {String} string The Unicode input string (UCS-2).\n\t * @returns {Array} The new array of code points.\n\t */\n\tfunction ucs2decode(string) {\n\t\tvar output = [],\n\t\t counter = 0,\n\t\t length = string.length,\n\t\t value,\n\t\t extra;\n\t\twhile (counter < length) {\n\t\t\tvalue = string.charCodeAt(counter++);\n\t\t\tif (value >= 0xD800 && value <= 0xDBFF && counter < length) {\n\t\t\t\t// high surrogate, and there is a next character\n\t\t\t\textra = string.charCodeAt(counter++);\n\t\t\t\tif ((extra & 0xFC00) == 0xDC00) { // low surrogate\n\t\t\t\t\toutput.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);\n\t\t\t\t} else {\n\t\t\t\t\t// unmatched surrogate; only append this code unit, in case the next\n\t\t\t\t\t// code unit is the high surrogate of a surrogate pair\n\t\t\t\t\toutput.push(value);\n\t\t\t\t\tcounter--;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\toutput.push(value);\n\t\t\t}\n\t\t}\n\t\treturn output;\n\t}\n\n\t/**\n\t * Creates a string based on an array of numeric code points.\n\t * @see `punycode.ucs2.decode`\n\t * @memberOf punycode.ucs2\n\t * @name encode\n\t * @param {Array} codePoints The array of numeric code points.\n\t * @returns {String} The new Unicode string (UCS-2).\n\t */\n\tfunction ucs2encode(array) {\n\t\treturn map(array, function(value) {\n\t\t\tvar output = '';\n\t\t\tif (value > 0xFFFF) {\n\t\t\t\tvalue -= 0x10000;\n\t\t\t\toutput += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);\n\t\t\t\tvalue = 0xDC00 | value & 0x3FF;\n\t\t\t}\n\t\t\toutput += stringFromCharCode(value);\n\t\t\treturn output;\n\t\t}).join('');\n\t}\n\n\t/**\n\t * Converts a basic code point into a digit/integer.\n\t * @see `digitToBasic()`\n\t * @private\n\t * @param {Number} codePoint The basic numeric code point value.\n\t * @returns {Number} The numeric value of a basic code point (for use in\n\t * representing integers) in the range `0` to `base - 1`, or `base` if\n\t * the code point does not represent a value.\n\t */\n\tfunction basicToDigit(codePoint) {\n\t\tif (codePoint - 48 < 10) {\n\t\t\treturn codePoint - 22;\n\t\t}\n\t\tif (codePoint - 65 < 26) {\n\t\t\treturn codePoint - 65;\n\t\t}\n\t\tif (codePoint - 97 < 26) {\n\t\t\treturn codePoint - 97;\n\t\t}\n\t\treturn base;\n\t}\n\n\t/**\n\t * Converts a digit/integer into a basic code point.\n\t * @see `basicToDigit()`\n\t * @private\n\t * @param {Number} digit The numeric value of a basic code point.\n\t * @returns {Number} The basic code point whose value (when used for\n\t * representing integers) is `digit`, which needs to be in the range\n\t * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is\n\t * used; else, the lowercase form is used. The behavior is undefined\n\t * if `flag` is non-zero and `digit` has no uppercase form.\n\t */\n\tfunction digitToBasic(digit, flag) {\n\t\t// 0..25 map to ASCII a..z or A..Z\n\t\t// 26..35 map to ASCII 0..9\n\t\treturn digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);\n\t}\n\n\t/**\n\t * Bias adaptation function as per section 3.4 of RFC 3492.\n\t * https://tools.ietf.org/html/rfc3492#section-3.4\n\t * @private\n\t */\n\tfunction adapt(delta, numPoints, firstTime) {\n\t\tvar k = 0;\n\t\tdelta = firstTime ? floor(delta / damp) : delta >> 1;\n\t\tdelta += floor(delta / numPoints);\n\t\tfor (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {\n\t\t\tdelta = floor(delta / baseMinusTMin);\n\t\t}\n\t\treturn floor(k + (baseMinusTMin + 1) * delta / (delta + skew));\n\t}\n\n\t/**\n\t * Converts a Punycode string of ASCII-only symbols to a string of Unicode\n\t * symbols.\n\t * @memberOf punycode\n\t * @param {String} input The Punycode string of ASCII-only symbols.\n\t * @returns {String} The resulting string of Unicode symbols.\n\t */\n\tfunction decode(input) {\n\t\t// Don't use UCS-2\n\t\tvar output = [],\n\t\t inputLength = input.length,\n\t\t out,\n\t\t i = 0,\n\t\t n = initialN,\n\t\t bias = initialBias,\n\t\t basic,\n\t\t j,\n\t\t index,\n\t\t oldi,\n\t\t w,\n\t\t k,\n\t\t digit,\n\t\t t,\n\t\t /** Cached calculation results */\n\t\t baseMinusT;\n\n\t\t// Handle the basic code points: let `basic` be the number of input code\n\t\t// points before the last delimiter, or `0` if there is none, then copy\n\t\t// the first basic code points to the output.\n\n\t\tbasic = input.lastIndexOf(delimiter);\n\t\tif (basic < 0) {\n\t\t\tbasic = 0;\n\t\t}\n\n\t\tfor (j = 0; j < basic; ++j) {\n\t\t\t// if it's not a basic code point\n\t\t\tif (input.charCodeAt(j) >= 0x80) {\n\t\t\t\terror('not-basic');\n\t\t\t}\n\t\t\toutput.push(input.charCodeAt(j));\n\t\t}\n\n\t\t// Main decoding loop: start just after the last delimiter if any basic code\n\t\t// points were copied; start at the beginning otherwise.\n\n\t\tfor (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {\n\n\t\t\t// `index` is the index of the next character to be consumed.\n\t\t\t// Decode a generalized variable-length integer into `delta`,\n\t\t\t// which gets added to `i`. The overflow checking is easier\n\t\t\t// if we increase `i` as we go, then subtract off its starting\n\t\t\t// value at the end to obtain `delta`.\n\t\t\tfor (oldi = i, w = 1, k = base; /* no condition */; k += base) {\n\n\t\t\t\tif (index >= inputLength) {\n\t\t\t\t\terror('invalid-input');\n\t\t\t\t}\n\n\t\t\t\tdigit = basicToDigit(input.charCodeAt(index++));\n\n\t\t\t\tif (digit >= base || digit > floor((maxInt - i) / w)) {\n\t\t\t\t\terror('overflow');\n\t\t\t\t}\n\n\t\t\t\ti += digit * w;\n\t\t\t\tt = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);\n\n\t\t\t\tif (digit < t) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tbaseMinusT = base - t;\n\t\t\t\tif (w > floor(maxInt / baseMinusT)) {\n\t\t\t\t\terror('overflow');\n\t\t\t\t}\n\n\t\t\t\tw *= baseMinusT;\n\n\t\t\t}\n\n\t\t\tout = output.length + 1;\n\t\t\tbias = adapt(i - oldi, out, oldi == 0);\n\n\t\t\t// `i` was supposed to wrap around from `out` to `0`,\n\t\t\t// incrementing `n` each time, so we'll fix that now:\n\t\t\tif (floor(i / out) > maxInt - n) {\n\t\t\t\terror('overflow');\n\t\t\t}\n\n\t\t\tn += floor(i / out);\n\t\t\ti %= out;\n\n\t\t\t// Insert `n` at position `i` of the output\n\t\t\toutput.splice(i++, 0, n);\n\n\t\t}\n\n\t\treturn ucs2encode(output);\n\t}\n\n\t/**\n\t * Converts a string of Unicode symbols (e.g. a domain name label) to a\n\t * Punycode string of ASCII-only symbols.\n\t * @memberOf punycode\n\t * @param {String} input The string of Unicode symbols.\n\t * @returns {String} The resulting Punycode string of ASCII-only symbols.\n\t */\n\tfunction encode(input) {\n\t\tvar n,\n\t\t delta,\n\t\t handledCPCount,\n\t\t basicLength,\n\t\t bias,\n\t\t j,\n\t\t m,\n\t\t q,\n\t\t k,\n\t\t t,\n\t\t currentValue,\n\t\t output = [],\n\t\t /** `inputLength` will hold the number of code points in `input`. */\n\t\t inputLength,\n\t\t /** Cached calculation results */\n\t\t handledCPCountPlusOne,\n\t\t baseMinusT,\n\t\t qMinusT;\n\n\t\t// Convert the input in UCS-2 to Unicode\n\t\tinput = ucs2decode(input);\n\n\t\t// Cache the length\n\t\tinputLength = input.length;\n\n\t\t// Initialize the state\n\t\tn = initialN;\n\t\tdelta = 0;\n\t\tbias = initialBias;\n\n\t\t// Handle the basic code points\n\t\tfor (j = 0; j < inputLength; ++j) {\n\t\t\tcurrentValue = input[j];\n\t\t\tif (currentValue < 0x80) {\n\t\t\t\toutput.push(stringFromCharCode(currentValue));\n\t\t\t}\n\t\t}\n\n\t\thandledCPCount = basicLength = output.length;\n\n\t\t// `handledCPCount` is the number of code points that have been handled;\n\t\t// `basicLength` is the number of basic code points.\n\n\t\t// Finish the basic string - if it is not empty - with a delimiter\n\t\tif (basicLength) {\n\t\t\toutput.push(delimiter);\n\t\t}\n\n\t\t// Main encoding loop:\n\t\twhile (handledCPCount < inputLength) {\n\n\t\t\t// All non-basic code points < n have been handled already. Find the next\n\t\t\t// larger one:\n\t\t\tfor (m = maxInt, j = 0; j < inputLength; ++j) {\n\t\t\t\tcurrentValue = input[j];\n\t\t\t\tif (currentValue >= n && currentValue < m) {\n\t\t\t\t\tm = currentValue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Increase `delta` enough to advance the decoder's state to ,\n\t\t\t// but guard against overflow\n\t\t\thandledCPCountPlusOne = handledCPCount + 1;\n\t\t\tif (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {\n\t\t\t\terror('overflow');\n\t\t\t}\n\n\t\t\tdelta += (m - n) * handledCPCountPlusOne;\n\t\t\tn = m;\n\n\t\t\tfor (j = 0; j < inputLength; ++j) {\n\t\t\t\tcurrentValue = input[j];\n\n\t\t\t\tif (currentValue < n && ++delta > maxInt) {\n\t\t\t\t\terror('overflow');\n\t\t\t\t}\n\n\t\t\t\tif (currentValue == n) {\n\t\t\t\t\t// Represent delta as a generalized variable-length integer\n\t\t\t\t\tfor (q = delta, k = base; /* no condition */; k += base) {\n\t\t\t\t\t\tt = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);\n\t\t\t\t\t\tif (q < t) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tqMinusT = q - t;\n\t\t\t\t\t\tbaseMinusT = base - t;\n\t\t\t\t\t\toutput.push(\n\t\t\t\t\t\t\tstringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))\n\t\t\t\t\t\t);\n\t\t\t\t\t\tq = floor(qMinusT / baseMinusT);\n\t\t\t\t\t}\n\n\t\t\t\t\toutput.push(stringFromCharCode(digitToBasic(q, 0)));\n\t\t\t\t\tbias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);\n\t\t\t\t\tdelta = 0;\n\t\t\t\t\t++handledCPCount;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t++delta;\n\t\t\t++n;\n\n\t\t}\n\t\treturn output.join('');\n\t}\n\n\t/**\n\t * Converts a Punycode string representing a domain name or an email address\n\t * to Unicode. Only the Punycoded parts of the input will be converted, i.e.\n\t * it doesn't matter if you call it on a string that has already been\n\t * converted to Unicode.\n\t * @memberOf punycode\n\t * @param {String} input The Punycoded domain name or email address to\n\t * convert to Unicode.\n\t * @returns {String} The Unicode representation of the given Punycode\n\t * string.\n\t */\n\tfunction toUnicode(input) {\n\t\treturn mapDomain(input, function(string) {\n\t\t\treturn regexPunycode.test(string)\n\t\t\t\t? decode(string.slice(4).toLowerCase())\n\t\t\t\t: string;\n\t\t});\n\t}\n\n\t/**\n\t * Converts a Unicode string representing a domain name or an email address to\n\t * Punycode. Only the non-ASCII parts of the domain name will be converted,\n\t * i.e. it doesn't matter if you call it with a domain that's already in\n\t * ASCII.\n\t * @memberOf punycode\n\t * @param {String} input The domain name or email address to convert, as a\n\t * Unicode string.\n\t * @returns {String} The Punycode representation of the given domain name or\n\t * email address.\n\t */\n\tfunction toASCII(input) {\n\t\treturn mapDomain(input, function(string) {\n\t\t\treturn regexNonASCII.test(string)\n\t\t\t\t? 'xn--' + encode(string)\n\t\t\t\t: string;\n\t\t});\n\t}\n\n\t/*--------------------------------------------------------------------------*/\n\n\t/** Define the public API */\n\tpunycode = {\n\t\t/**\n\t\t * A string representing the current Punycode.js version number.\n\t\t * @memberOf punycode\n\t\t * @type String\n\t\t */\n\t\t'version': '1.4.1',\n\t\t/**\n\t\t * An object of methods to convert from JavaScript's internal character\n\t\t * representation (UCS-2) to Unicode code points, and back.\n\t\t * @see \n\t\t * @memberOf punycode\n\t\t * @type Object\n\t\t */\n\t\t'ucs2': {\n\t\t\t'decode': ucs2decode,\n\t\t\t'encode': ucs2encode\n\t\t},\n\t\t'decode': decode,\n\t\t'encode': encode,\n\t\t'toASCII': toASCII,\n\t\t'toUnicode': toUnicode\n\t};\n\n\t/** Expose `punycode` */\n\t// Some AMD build optimizers, like r.js, check for specific condition patterns\n\t// like the following:\n\tif (\n\t\ttrue\n\t) {\n\t\t!(__WEBPACK_AMD_DEFINE_RESULT__ = (function() {\n\t\t\treturn punycode;\n\t\t}).call(exports, __webpack_require__, exports, module),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));\n\t} else {}\n\n}(this));\n\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../webpack/buildin/module.js */ \"../../node_modules/webpack/buildin/module.js\")(module), __webpack_require__(/*! ./../webpack/buildin/global.js */ \"../../node_modules/webpack/buildin/global.js\")))\n\n//# sourceURL=webpack:////Users/matb/projects/vscode/node_modules/punycode/punycode.js?"); - -/***/ }), - -/***/ "../../node_modules/webpack/buildin/global.js": -/*!***********************************!*\ - !*** (webpack)/buildin/global.js ***! - \***********************************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -eval("var g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn this;\n})();\n\ntry {\n\t// This works if eval is allowed (see CSP)\n\tg = g || new Function(\"return this\")();\n} catch (e) {\n\t// This works if the window reference is available\n\tif (typeof window === \"object\") g = window;\n}\n\n// g can still be undefined, but nothing to do about it...\n// We return undefined, instead of nothing here, so it's\n// easier to handle this case. if(!global) { ...}\n\nmodule.exports = g;\n\n\n//# sourceURL=webpack:///(webpack)/buildin/global.js?"); - -/***/ }), - -/***/ "../../node_modules/webpack/buildin/module.js": -/*!***********************************!*\ - !*** (webpack)/buildin/module.js ***! - \***********************************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -eval("module.exports = function(module) {\n\tif (!module.webpackPolyfill) {\n\t\tmodule.deprecate = function() {};\n\t\tmodule.paths = [];\n\t\t// module.parent = undefined by default\n\t\tif (!module.children) module.children = [];\n\t\tObject.defineProperty(module, \"loaded\", {\n\t\t\tenumerable: true,\n\t\t\tget: function() {\n\t\t\t\treturn module.l;\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(module, \"id\", {\n\t\t\tenumerable: true,\n\t\t\tget: function() {\n\t\t\t\treturn module.i;\n\t\t\t}\n\t\t});\n\t\tmodule.webpackPolyfill = 1;\n\t}\n\treturn module;\n};\n\n\n//# sourceURL=webpack:///(webpack)/buildin/module.js?"); - -/***/ }), - -/***/ "./node_modules/entities/lib/maps/entities.json": -/*!******************************************************!*\ - !*** ./node_modules/entities/lib/maps/entities.json ***! - \******************************************************/ -/*! exports provided: Aacute, aacute, Abreve, abreve, ac, acd, acE, Acirc, acirc, acute, Acy, acy, AElig, aelig, af, Afr, afr, Agrave, agrave, alefsym, aleph, Alpha, alpha, Amacr, amacr, amalg, amp, AMP, andand, And, and, andd, andslope, andv, ang, ange, angle, angmsdaa, angmsdab, angmsdac, angmsdad, angmsdae, angmsdaf, angmsdag, angmsdah, angmsd, angrt, angrtvb, angrtvbd, angsph, angst, angzarr, Aogon, aogon, Aopf, aopf, apacir, ap, apE, ape, apid, apos, ApplyFunction, approx, approxeq, Aring, aring, Ascr, ascr, Assign, ast, asymp, asympeq, Atilde, atilde, Auml, auml, awconint, awint, backcong, backepsilon, backprime, backsim, backsimeq, Backslash, Barv, barvee, barwed, Barwed, barwedge, bbrk, bbrktbrk, bcong, Bcy, bcy, bdquo, becaus, because, Because, bemptyv, bepsi, bernou, Bernoullis, Beta, beta, beth, between, Bfr, bfr, bigcap, bigcirc, bigcup, bigodot, bigoplus, bigotimes, bigsqcup, bigstar, bigtriangledown, bigtriangleup, biguplus, bigvee, bigwedge, bkarow, blacklozenge, blacksquare, blacktriangle, blacktriangledown, blacktriangleleft, blacktriangleright, blank, blk12, blk14, blk34, block, bne, bnequiv, bNot, bnot, Bopf, bopf, bot, bottom, bowtie, boxbox, boxdl, boxdL, boxDl, boxDL, boxdr, boxdR, boxDr, boxDR, boxh, boxH, boxhd, boxHd, boxhD, boxHD, boxhu, boxHu, boxhU, boxHU, boxminus, boxplus, boxtimes, boxul, boxuL, boxUl, boxUL, boxur, boxuR, boxUr, boxUR, boxv, boxV, boxvh, boxvH, boxVh, boxVH, boxvl, boxvL, boxVl, boxVL, boxvr, boxvR, boxVr, boxVR, bprime, breve, Breve, brvbar, bscr, Bscr, bsemi, bsim, bsime, bsolb, bsol, bsolhsub, bull, bullet, bump, bumpE, bumpe, Bumpeq, bumpeq, Cacute, cacute, capand, capbrcup, capcap, cap, Cap, capcup, capdot, CapitalDifferentialD, caps, caret, caron, Cayleys, ccaps, Ccaron, ccaron, Ccedil, ccedil, Ccirc, ccirc, Cconint, ccups, ccupssm, Cdot, cdot, cedil, Cedilla, cemptyv, cent, centerdot, CenterDot, cfr, Cfr, CHcy, chcy, check, checkmark, Chi, chi, circ, circeq, circlearrowleft, circlearrowright, circledast, circledcirc, circleddash, CircleDot, circledR, circledS, CircleMinus, CirclePlus, CircleTimes, cir, cirE, cire, cirfnint, cirmid, cirscir, ClockwiseContourIntegral, CloseCurlyDoubleQuote, CloseCurlyQuote, clubs, clubsuit, colon, Colon, Colone, colone, coloneq, comma, commat, comp, compfn, complement, complexes, cong, congdot, Congruent, conint, Conint, ContourIntegral, copf, Copf, coprod, Coproduct, copy, COPY, copysr, CounterClockwiseContourIntegral, crarr, cross, Cross, Cscr, cscr, csub, csube, csup, csupe, ctdot, cudarrl, cudarrr, cuepr, cuesc, cularr, cularrp, cupbrcap, cupcap, CupCap, cup, Cup, cupcup, cupdot, cupor, cups, curarr, curarrm, curlyeqprec, curlyeqsucc, curlyvee, curlywedge, curren, curvearrowleft, curvearrowright, cuvee, cuwed, cwconint, cwint, cylcty, dagger, Dagger, daleth, darr, Darr, dArr, dash, Dashv, dashv, dbkarow, dblac, Dcaron, dcaron, Dcy, dcy, ddagger, ddarr, DD, dd, DDotrahd, ddotseq, deg, Del, Delta, delta, demptyv, dfisht, Dfr, dfr, dHar, dharl, dharr, DiacriticalAcute, DiacriticalDot, DiacriticalDoubleAcute, DiacriticalGrave, DiacriticalTilde, diam, diamond, Diamond, diamondsuit, diams, die, DifferentialD, digamma, disin, div, divide, divideontimes, divonx, DJcy, djcy, dlcorn, dlcrop, dollar, Dopf, dopf, Dot, dot, DotDot, doteq, doteqdot, DotEqual, dotminus, dotplus, dotsquare, doublebarwedge, DoubleContourIntegral, DoubleDot, DoubleDownArrow, DoubleLeftArrow, DoubleLeftRightArrow, DoubleLeftTee, DoubleLongLeftArrow, DoubleLongLeftRightArrow, DoubleLongRightArrow, DoubleRightArrow, DoubleRightTee, DoubleUpArrow, DoubleUpDownArrow, DoubleVerticalBar, DownArrowBar, downarrow, DownArrow, Downarrow, DownArrowUpArrow, DownBreve, downdownarrows, downharpoonleft, downharpoonright, DownLeftRightVector, DownLeftTeeVector, DownLeftVectorBar, DownLeftVector, DownRightTeeVector, DownRightVectorBar, DownRightVector, DownTeeArrow, DownTee, drbkarow, drcorn, drcrop, Dscr, dscr, DScy, dscy, dsol, Dstrok, dstrok, dtdot, dtri, dtrif, duarr, duhar, dwangle, DZcy, dzcy, dzigrarr, Eacute, eacute, easter, Ecaron, ecaron, Ecirc, ecirc, ecir, ecolon, Ecy, ecy, eDDot, Edot, edot, eDot, ee, efDot, Efr, efr, eg, Egrave, egrave, egs, egsdot, el, Element, elinters, ell, els, elsdot, Emacr, emacr, empty, emptyset, EmptySmallSquare, emptyv, EmptyVerySmallSquare, emsp13, emsp14, emsp, ENG, eng, ensp, Eogon, eogon, Eopf, eopf, epar, eparsl, eplus, epsi, Epsilon, epsilon, epsiv, eqcirc, eqcolon, eqsim, eqslantgtr, eqslantless, Equal, equals, EqualTilde, equest, Equilibrium, equiv, equivDD, eqvparsl, erarr, erDot, escr, Escr, esdot, Esim, esim, Eta, eta, ETH, eth, Euml, euml, euro, excl, exist, Exists, expectation, exponentiale, ExponentialE, fallingdotseq, Fcy, fcy, female, ffilig, fflig, ffllig, Ffr, ffr, filig, FilledSmallSquare, FilledVerySmallSquare, fjlig, flat, fllig, fltns, fnof, Fopf, fopf, forall, ForAll, fork, forkv, Fouriertrf, fpartint, frac12, frac13, frac14, frac15, frac16, frac18, frac23, frac25, frac34, frac35, frac38, frac45, frac56, frac58, frac78, frasl, frown, fscr, Fscr, gacute, Gamma, gamma, Gammad, gammad, gap, Gbreve, gbreve, Gcedil, Gcirc, gcirc, Gcy, gcy, Gdot, gdot, ge, gE, gEl, gel, geq, geqq, geqslant, gescc, ges, gesdot, gesdoto, gesdotol, gesl, gesles, Gfr, gfr, gg, Gg, ggg, gimel, GJcy, gjcy, gla, gl, glE, glj, gnap, gnapprox, gne, gnE, gneq, gneqq, gnsim, Gopf, gopf, grave, GreaterEqual, GreaterEqualLess, GreaterFullEqual, GreaterGreater, GreaterLess, GreaterSlantEqual, GreaterTilde, Gscr, gscr, gsim, gsime, gsiml, gtcc, gtcir, gt, GT, Gt, gtdot, gtlPar, gtquest, gtrapprox, gtrarr, gtrdot, gtreqless, gtreqqless, gtrless, gtrsim, gvertneqq, gvnE, Hacek, hairsp, half, hamilt, HARDcy, hardcy, harrcir, harr, hArr, harrw, Hat, hbar, Hcirc, hcirc, hearts, heartsuit, hellip, hercon, hfr, Hfr, HilbertSpace, hksearow, hkswarow, hoarr, homtht, hookleftarrow, hookrightarrow, hopf, Hopf, horbar, HorizontalLine, hscr, Hscr, hslash, Hstrok, hstrok, HumpDownHump, HumpEqual, hybull, hyphen, Iacute, iacute, ic, Icirc, icirc, Icy, icy, Idot, IEcy, iecy, iexcl, iff, ifr, Ifr, Igrave, igrave, ii, iiiint, iiint, iinfin, iiota, IJlig, ijlig, Imacr, imacr, image, ImaginaryI, imagline, imagpart, imath, Im, imof, imped, Implies, incare, in, infin, infintie, inodot, intcal, int, Int, integers, Integral, intercal, Intersection, intlarhk, intprod, InvisibleComma, InvisibleTimes, IOcy, iocy, Iogon, iogon, Iopf, iopf, Iota, iota, iprod, iquest, iscr, Iscr, isin, isindot, isinE, isins, isinsv, isinv, it, Itilde, itilde, Iukcy, iukcy, Iuml, iuml, Jcirc, jcirc, Jcy, jcy, Jfr, jfr, jmath, Jopf, jopf, Jscr, jscr, Jsercy, jsercy, Jukcy, jukcy, Kappa, kappa, kappav, Kcedil, kcedil, Kcy, kcy, Kfr, kfr, kgreen, KHcy, khcy, KJcy, kjcy, Kopf, kopf, Kscr, kscr, lAarr, Lacute, lacute, laemptyv, lagran, Lambda, lambda, lang, Lang, langd, langle, lap, Laplacetrf, laquo, larrb, larrbfs, larr, Larr, lArr, larrfs, larrhk, larrlp, larrpl, larrsim, larrtl, latail, lAtail, lat, late, lates, lbarr, lBarr, lbbrk, lbrace, lbrack, lbrke, lbrksld, lbrkslu, Lcaron, lcaron, Lcedil, lcedil, lceil, lcub, Lcy, lcy, ldca, ldquo, ldquor, ldrdhar, ldrushar, ldsh, le, lE, LeftAngleBracket, LeftArrowBar, leftarrow, LeftArrow, Leftarrow, LeftArrowRightArrow, leftarrowtail, LeftCeiling, LeftDoubleBracket, LeftDownTeeVector, LeftDownVectorBar, LeftDownVector, LeftFloor, leftharpoondown, leftharpoonup, leftleftarrows, leftrightarrow, LeftRightArrow, Leftrightarrow, leftrightarrows, leftrightharpoons, leftrightsquigarrow, LeftRightVector, LeftTeeArrow, LeftTee, LeftTeeVector, leftthreetimes, LeftTriangleBar, LeftTriangle, LeftTriangleEqual, LeftUpDownVector, LeftUpTeeVector, LeftUpVectorBar, LeftUpVector, LeftVectorBar, LeftVector, lEg, leg, leq, leqq, leqslant, lescc, les, lesdot, lesdoto, lesdotor, lesg, lesges, lessapprox, lessdot, lesseqgtr, lesseqqgtr, LessEqualGreater, LessFullEqual, LessGreater, lessgtr, LessLess, lesssim, LessSlantEqual, LessTilde, lfisht, lfloor, Lfr, lfr, lg, lgE, lHar, lhard, lharu, lharul, lhblk, LJcy, ljcy, llarr, ll, Ll, llcorner, Lleftarrow, llhard, lltri, Lmidot, lmidot, lmoustache, lmoust, lnap, lnapprox, lne, lnE, lneq, lneqq, lnsim, loang, loarr, lobrk, longleftarrow, LongLeftArrow, Longleftarrow, longleftrightarrow, LongLeftRightArrow, Longleftrightarrow, longmapsto, longrightarrow, LongRightArrow, Longrightarrow, looparrowleft, looparrowright, lopar, Lopf, lopf, loplus, lotimes, lowast, lowbar, LowerLeftArrow, LowerRightArrow, loz, lozenge, lozf, lpar, lparlt, lrarr, lrcorner, lrhar, lrhard, lrm, lrtri, lsaquo, lscr, Lscr, lsh, Lsh, lsim, lsime, lsimg, lsqb, lsquo, lsquor, Lstrok, lstrok, ltcc, ltcir, lt, LT, Lt, ltdot, lthree, ltimes, ltlarr, ltquest, ltri, ltrie, ltrif, ltrPar, lurdshar, luruhar, lvertneqq, lvnE, macr, male, malt, maltese, Map, map, mapsto, mapstodown, mapstoleft, mapstoup, marker, mcomma, Mcy, mcy, mdash, mDDot, measuredangle, MediumSpace, Mellintrf, Mfr, mfr, mho, micro, midast, midcir, mid, middot, minusb, minus, minusd, minusdu, MinusPlus, mlcp, mldr, mnplus, models, Mopf, mopf, mp, mscr, Mscr, mstpos, Mu, mu, multimap, mumap, nabla, Nacute, nacute, nang, nap, napE, napid, napos, napprox, natural, naturals, natur, nbsp, nbump, nbumpe, ncap, Ncaron, ncaron, Ncedil, ncedil, ncong, ncongdot, ncup, Ncy, ncy, ndash, nearhk, nearr, neArr, nearrow, ne, nedot, NegativeMediumSpace, NegativeThickSpace, NegativeThinSpace, NegativeVeryThinSpace, nequiv, nesear, nesim, NestedGreaterGreater, NestedLessLess, NewLine, nexist, nexists, Nfr, nfr, ngE, nge, ngeq, ngeqq, ngeqslant, nges, nGg, ngsim, nGt, ngt, ngtr, nGtv, nharr, nhArr, nhpar, ni, nis, nisd, niv, NJcy, njcy, nlarr, nlArr, nldr, nlE, nle, nleftarrow, nLeftarrow, nleftrightarrow, nLeftrightarrow, nleq, nleqq, nleqslant, nles, nless, nLl, nlsim, nLt, nlt, nltri, nltrie, nLtv, nmid, NoBreak, NonBreakingSpace, nopf, Nopf, Not, not, NotCongruent, NotCupCap, NotDoubleVerticalBar, NotElement, NotEqual, NotEqualTilde, NotExists, NotGreater, NotGreaterEqual, NotGreaterFullEqual, NotGreaterGreater, NotGreaterLess, NotGreaterSlantEqual, NotGreaterTilde, NotHumpDownHump, NotHumpEqual, notin, notindot, notinE, notinva, notinvb, notinvc, NotLeftTriangleBar, NotLeftTriangle, NotLeftTriangleEqual, NotLess, NotLessEqual, NotLessGreater, NotLessLess, NotLessSlantEqual, NotLessTilde, NotNestedGreaterGreater, NotNestedLessLess, notni, notniva, notnivb, notnivc, NotPrecedes, NotPrecedesEqual, NotPrecedesSlantEqual, NotReverseElement, NotRightTriangleBar, NotRightTriangle, NotRightTriangleEqual, NotSquareSubset, NotSquareSubsetEqual, NotSquareSuperset, NotSquareSupersetEqual, NotSubset, NotSubsetEqual, NotSucceeds, NotSucceedsEqual, NotSucceedsSlantEqual, NotSucceedsTilde, NotSuperset, NotSupersetEqual, NotTilde, NotTildeEqual, NotTildeFullEqual, NotTildeTilde, NotVerticalBar, nparallel, npar, nparsl, npart, npolint, npr, nprcue, nprec, npreceq, npre, nrarrc, nrarr, nrArr, nrarrw, nrightarrow, nRightarrow, nrtri, nrtrie, nsc, nsccue, nsce, Nscr, nscr, nshortmid, nshortparallel, nsim, nsime, nsimeq, nsmid, nspar, nsqsube, nsqsupe, nsub, nsubE, nsube, nsubset, nsubseteq, nsubseteqq, nsucc, nsucceq, nsup, nsupE, nsupe, nsupset, nsupseteq, nsupseteqq, ntgl, Ntilde, ntilde, ntlg, ntriangleleft, ntrianglelefteq, ntriangleright, ntrianglerighteq, Nu, nu, num, numero, numsp, nvap, nvdash, nvDash, nVdash, nVDash, nvge, nvgt, nvHarr, nvinfin, nvlArr, nvle, nvlt, nvltrie, nvrArr, nvrtrie, nvsim, nwarhk, nwarr, nwArr, nwarrow, nwnear, Oacute, oacute, oast, Ocirc, ocirc, ocir, Ocy, ocy, odash, Odblac, odblac, odiv, odot, odsold, OElig, oelig, ofcir, Ofr, ofr, ogon, Ograve, ograve, ogt, ohbar, ohm, oint, olarr, olcir, olcross, oline, olt, Omacr, omacr, Omega, omega, Omicron, omicron, omid, ominus, Oopf, oopf, opar, OpenCurlyDoubleQuote, OpenCurlyQuote, operp, oplus, orarr, Or, or, ord, order, orderof, ordf, ordm, origof, oror, orslope, orv, oS, Oscr, oscr, Oslash, oslash, osol, Otilde, otilde, otimesas, Otimes, otimes, Ouml, ouml, ovbar, OverBar, OverBrace, OverBracket, OverParenthesis, para, parallel, par, parsim, parsl, part, PartialD, Pcy, pcy, percnt, period, permil, perp, pertenk, Pfr, pfr, Phi, phi, phiv, phmmat, phone, Pi, pi, pitchfork, piv, planck, planckh, plankv, plusacir, plusb, pluscir, plus, plusdo, plusdu, pluse, PlusMinus, plusmn, plussim, plustwo, pm, Poincareplane, pointint, popf, Popf, pound, prap, Pr, pr, prcue, precapprox, prec, preccurlyeq, Precedes, PrecedesEqual, PrecedesSlantEqual, PrecedesTilde, preceq, precnapprox, precneqq, precnsim, pre, prE, precsim, prime, Prime, primes, prnap, prnE, prnsim, prod, Product, profalar, profline, profsurf, prop, Proportional, Proportion, propto, prsim, prurel, Pscr, pscr, Psi, psi, puncsp, Qfr, qfr, qint, qopf, Qopf, qprime, Qscr, qscr, quaternions, quatint, quest, questeq, quot, QUOT, rAarr, race, Racute, racute, radic, raemptyv, rang, Rang, rangd, range, rangle, raquo, rarrap, rarrb, rarrbfs, rarrc, rarr, Rarr, rArr, rarrfs, rarrhk, rarrlp, rarrpl, rarrsim, Rarrtl, rarrtl, rarrw, ratail, rAtail, ratio, rationals, rbarr, rBarr, RBarr, rbbrk, rbrace, rbrack, rbrke, rbrksld, rbrkslu, Rcaron, rcaron, Rcedil, rcedil, rceil, rcub, Rcy, rcy, rdca, rdldhar, rdquo, rdquor, rdsh, real, realine, realpart, reals, Re, rect, reg, REG, ReverseElement, ReverseEquilibrium, ReverseUpEquilibrium, rfisht, rfloor, rfr, Rfr, rHar, rhard, rharu, rharul, Rho, rho, rhov, RightAngleBracket, RightArrowBar, rightarrow, RightArrow, Rightarrow, RightArrowLeftArrow, rightarrowtail, RightCeiling, RightDoubleBracket, RightDownTeeVector, RightDownVectorBar, RightDownVector, RightFloor, rightharpoondown, rightharpoonup, rightleftarrows, rightleftharpoons, rightrightarrows, rightsquigarrow, RightTeeArrow, RightTee, RightTeeVector, rightthreetimes, RightTriangleBar, RightTriangle, RightTriangleEqual, RightUpDownVector, RightUpTeeVector, RightUpVectorBar, RightUpVector, RightVectorBar, RightVector, ring, risingdotseq, rlarr, rlhar, rlm, rmoustache, rmoust, rnmid, roang, roarr, robrk, ropar, ropf, Ropf, roplus, rotimes, RoundImplies, rpar, rpargt, rppolint, rrarr, Rrightarrow, rsaquo, rscr, Rscr, rsh, Rsh, rsqb, rsquo, rsquor, rthree, rtimes, rtri, rtrie, rtrif, rtriltri, RuleDelayed, ruluhar, rx, Sacute, sacute, sbquo, scap, Scaron, scaron, Sc, sc, sccue, sce, scE, Scedil, scedil, Scirc, scirc, scnap, scnE, scnsim, scpolint, scsim, Scy, scy, sdotb, sdot, sdote, searhk, searr, seArr, searrow, sect, semi, seswar, setminus, setmn, sext, Sfr, sfr, sfrown, sharp, SHCHcy, shchcy, SHcy, shcy, ShortDownArrow, ShortLeftArrow, shortmid, shortparallel, ShortRightArrow, ShortUpArrow, shy, Sigma, sigma, sigmaf, sigmav, sim, simdot, sime, simeq, simg, simgE, siml, simlE, simne, simplus, simrarr, slarr, SmallCircle, smallsetminus, smashp, smeparsl, smid, smile, smt, smte, smtes, SOFTcy, softcy, solbar, solb, sol, Sopf, sopf, spades, spadesuit, spar, sqcap, sqcaps, sqcup, sqcups, Sqrt, sqsub, sqsube, sqsubset, sqsubseteq, sqsup, sqsupe, sqsupset, sqsupseteq, square, Square, SquareIntersection, SquareSubset, SquareSubsetEqual, SquareSuperset, SquareSupersetEqual, SquareUnion, squarf, squ, squf, srarr, Sscr, sscr, ssetmn, ssmile, sstarf, Star, star, starf, straightepsilon, straightphi, strns, sub, Sub, subdot, subE, sube, subedot, submult, subnE, subne, subplus, subrarr, subset, Subset, subseteq, subseteqq, SubsetEqual, subsetneq, subsetneqq, subsim, subsub, subsup, succapprox, succ, succcurlyeq, Succeeds, SucceedsEqual, SucceedsSlantEqual, SucceedsTilde, succeq, succnapprox, succneqq, succnsim, succsim, SuchThat, sum, Sum, sung, sup1, sup2, sup3, sup, Sup, supdot, supdsub, supE, supe, supedot, Superset, SupersetEqual, suphsol, suphsub, suplarr, supmult, supnE, supne, supplus, supset, Supset, supseteq, supseteqq, supsetneq, supsetneqq, supsim, supsub, supsup, swarhk, swarr, swArr, swarrow, swnwar, szlig, Tab, target, Tau, tau, tbrk, Tcaron, tcaron, Tcedil, tcedil, Tcy, tcy, tdot, telrec, Tfr, tfr, there4, therefore, Therefore, Theta, theta, thetasym, thetav, thickapprox, thicksim, ThickSpace, ThinSpace, thinsp, thkap, thksim, THORN, thorn, tilde, Tilde, TildeEqual, TildeFullEqual, TildeTilde, timesbar, timesb, times, timesd, tint, toea, topbot, topcir, top, Topf, topf, topfork, tosa, tprime, trade, TRADE, triangle, triangledown, triangleleft, trianglelefteq, triangleq, triangleright, trianglerighteq, tridot, trie, triminus, TripleDot, triplus, trisb, tritime, trpezium, Tscr, tscr, TScy, tscy, TSHcy, tshcy, Tstrok, tstrok, twixt, twoheadleftarrow, twoheadrightarrow, Uacute, uacute, uarr, Uarr, uArr, Uarrocir, Ubrcy, ubrcy, Ubreve, ubreve, Ucirc, ucirc, Ucy, ucy, udarr, Udblac, udblac, udhar, ufisht, Ufr, ufr, Ugrave, ugrave, uHar, uharl, uharr, uhblk, ulcorn, ulcorner, ulcrop, ultri, Umacr, umacr, uml, UnderBar, UnderBrace, UnderBracket, UnderParenthesis, Union, UnionPlus, Uogon, uogon, Uopf, uopf, UpArrowBar, uparrow, UpArrow, Uparrow, UpArrowDownArrow, updownarrow, UpDownArrow, Updownarrow, UpEquilibrium, upharpoonleft, upharpoonright, uplus, UpperLeftArrow, UpperRightArrow, upsi, Upsi, upsih, Upsilon, upsilon, UpTeeArrow, UpTee, upuparrows, urcorn, urcorner, urcrop, Uring, uring, urtri, Uscr, uscr, utdot, Utilde, utilde, utri, utrif, uuarr, Uuml, uuml, uwangle, vangrt, varepsilon, varkappa, varnothing, varphi, varpi, varpropto, varr, vArr, varrho, varsigma, varsubsetneq, varsubsetneqq, varsupsetneq, varsupsetneqq, vartheta, vartriangleleft, vartriangleright, vBar, Vbar, vBarv, Vcy, vcy, vdash, vDash, Vdash, VDash, Vdashl, veebar, vee, Vee, veeeq, vellip, verbar, Verbar, vert, Vert, VerticalBar, VerticalLine, VerticalSeparator, VerticalTilde, VeryThinSpace, Vfr, vfr, vltri, vnsub, vnsup, Vopf, vopf, vprop, vrtri, Vscr, vscr, vsubnE, vsubne, vsupnE, vsupne, Vvdash, vzigzag, Wcirc, wcirc, wedbar, wedge, Wedge, wedgeq, weierp, Wfr, wfr, Wopf, wopf, wp, wr, wreath, Wscr, wscr, xcap, xcirc, xcup, xdtri, Xfr, xfr, xharr, xhArr, Xi, xi, xlarr, xlArr, xmap, xnis, xodot, Xopf, xopf, xoplus, xotime, xrarr, xrArr, Xscr, xscr, xsqcup, xuplus, xutri, xvee, xwedge, Yacute, yacute, YAcy, yacy, Ycirc, ycirc, Ycy, ycy, yen, Yfr, yfr, YIcy, yicy, Yopf, yopf, Yscr, yscr, YUcy, yucy, yuml, Yuml, Zacute, zacute, Zcaron, zcaron, Zcy, zcy, Zdot, zdot, zeetrf, ZeroWidthSpace, Zeta, zeta, zfr, Zfr, ZHcy, zhcy, zigrarr, zopf, Zopf, Zscr, zscr, zwj, zwnj, default */ -/***/ (function(module) { - -eval("module.exports = JSON.parse(\"{\\\"Aacute\\\":\\\"Á\\\",\\\"aacute\\\":\\\"á\\\",\\\"Abreve\\\":\\\"Ă\\\",\\\"abreve\\\":\\\"ă\\\",\\\"ac\\\":\\\"∾\\\",\\\"acd\\\":\\\"∿\\\",\\\"acE\\\":\\\"∾̳\\\",\\\"Acirc\\\":\\\"Â\\\",\\\"acirc\\\":\\\"â\\\",\\\"acute\\\":\\\"´\\\",\\\"Acy\\\":\\\"А\\\",\\\"acy\\\":\\\"а\\\",\\\"AElig\\\":\\\"Æ\\\",\\\"aelig\\\":\\\"æ\\\",\\\"af\\\":\\\"⁡\\\",\\\"Afr\\\":\\\"𝔄\\\",\\\"afr\\\":\\\"𝔞\\\",\\\"Agrave\\\":\\\"À\\\",\\\"agrave\\\":\\\"à\\\",\\\"alefsym\\\":\\\"ℵ\\\",\\\"aleph\\\":\\\"ℵ\\\",\\\"Alpha\\\":\\\"Α\\\",\\\"alpha\\\":\\\"α\\\",\\\"Amacr\\\":\\\"Ā\\\",\\\"amacr\\\":\\\"ā\\\",\\\"amalg\\\":\\\"⨿\\\",\\\"amp\\\":\\\"&\\\",\\\"AMP\\\":\\\"&\\\",\\\"andand\\\":\\\"⩕\\\",\\\"And\\\":\\\"⩓\\\",\\\"and\\\":\\\"∧\\\",\\\"andd\\\":\\\"⩜\\\",\\\"andslope\\\":\\\"⩘\\\",\\\"andv\\\":\\\"⩚\\\",\\\"ang\\\":\\\"∠\\\",\\\"ange\\\":\\\"⦤\\\",\\\"angle\\\":\\\"∠\\\",\\\"angmsdaa\\\":\\\"⦨\\\",\\\"angmsdab\\\":\\\"⦩\\\",\\\"angmsdac\\\":\\\"⦪\\\",\\\"angmsdad\\\":\\\"⦫\\\",\\\"angmsdae\\\":\\\"⦬\\\",\\\"angmsdaf\\\":\\\"⦭\\\",\\\"angmsdag\\\":\\\"⦮\\\",\\\"angmsdah\\\":\\\"⦯\\\",\\\"angmsd\\\":\\\"∡\\\",\\\"angrt\\\":\\\"∟\\\",\\\"angrtvb\\\":\\\"⊾\\\",\\\"angrtvbd\\\":\\\"⦝\\\",\\\"angsph\\\":\\\"∢\\\",\\\"angst\\\":\\\"Å\\\",\\\"angzarr\\\":\\\"⍼\\\",\\\"Aogon\\\":\\\"Ą\\\",\\\"aogon\\\":\\\"ą\\\",\\\"Aopf\\\":\\\"𝔸\\\",\\\"aopf\\\":\\\"𝕒\\\",\\\"apacir\\\":\\\"⩯\\\",\\\"ap\\\":\\\"≈\\\",\\\"apE\\\":\\\"⩰\\\",\\\"ape\\\":\\\"≊\\\",\\\"apid\\\":\\\"≋\\\",\\\"apos\\\":\\\"'\\\",\\\"ApplyFunction\\\":\\\"⁡\\\",\\\"approx\\\":\\\"≈\\\",\\\"approxeq\\\":\\\"≊\\\",\\\"Aring\\\":\\\"Å\\\",\\\"aring\\\":\\\"å\\\",\\\"Ascr\\\":\\\"𝒜\\\",\\\"ascr\\\":\\\"𝒶\\\",\\\"Assign\\\":\\\"≔\\\",\\\"ast\\\":\\\"*\\\",\\\"asymp\\\":\\\"≈\\\",\\\"asympeq\\\":\\\"≍\\\",\\\"Atilde\\\":\\\"Ã\\\",\\\"atilde\\\":\\\"ã\\\",\\\"Auml\\\":\\\"Ä\\\",\\\"auml\\\":\\\"ä\\\",\\\"awconint\\\":\\\"∳\\\",\\\"awint\\\":\\\"⨑\\\",\\\"backcong\\\":\\\"≌\\\",\\\"backepsilon\\\":\\\"϶\\\",\\\"backprime\\\":\\\"‵\\\",\\\"backsim\\\":\\\"∽\\\",\\\"backsimeq\\\":\\\"⋍\\\",\\\"Backslash\\\":\\\"∖\\\",\\\"Barv\\\":\\\"⫧\\\",\\\"barvee\\\":\\\"⊽\\\",\\\"barwed\\\":\\\"⌅\\\",\\\"Barwed\\\":\\\"⌆\\\",\\\"barwedge\\\":\\\"⌅\\\",\\\"bbrk\\\":\\\"⎵\\\",\\\"bbrktbrk\\\":\\\"⎶\\\",\\\"bcong\\\":\\\"≌\\\",\\\"Bcy\\\":\\\"Б\\\",\\\"bcy\\\":\\\"б\\\",\\\"bdquo\\\":\\\"„\\\",\\\"becaus\\\":\\\"∵\\\",\\\"because\\\":\\\"∵\\\",\\\"Because\\\":\\\"∵\\\",\\\"bemptyv\\\":\\\"⦰\\\",\\\"bepsi\\\":\\\"϶\\\",\\\"bernou\\\":\\\"ℬ\\\",\\\"Bernoullis\\\":\\\"ℬ\\\",\\\"Beta\\\":\\\"Β\\\",\\\"beta\\\":\\\"β\\\",\\\"beth\\\":\\\"ℶ\\\",\\\"between\\\":\\\"≬\\\",\\\"Bfr\\\":\\\"𝔅\\\",\\\"bfr\\\":\\\"𝔟\\\",\\\"bigcap\\\":\\\"⋂\\\",\\\"bigcirc\\\":\\\"◯\\\",\\\"bigcup\\\":\\\"⋃\\\",\\\"bigodot\\\":\\\"⨀\\\",\\\"bigoplus\\\":\\\"⨁\\\",\\\"bigotimes\\\":\\\"⨂\\\",\\\"bigsqcup\\\":\\\"⨆\\\",\\\"bigstar\\\":\\\"★\\\",\\\"bigtriangledown\\\":\\\"▽\\\",\\\"bigtriangleup\\\":\\\"△\\\",\\\"biguplus\\\":\\\"⨄\\\",\\\"bigvee\\\":\\\"⋁\\\",\\\"bigwedge\\\":\\\"⋀\\\",\\\"bkarow\\\":\\\"⤍\\\",\\\"blacklozenge\\\":\\\"⧫\\\",\\\"blacksquare\\\":\\\"▪\\\",\\\"blacktriangle\\\":\\\"▴\\\",\\\"blacktriangledown\\\":\\\"▾\\\",\\\"blacktriangleleft\\\":\\\"◂\\\",\\\"blacktriangleright\\\":\\\"▸\\\",\\\"blank\\\":\\\"␣\\\",\\\"blk12\\\":\\\"▒\\\",\\\"blk14\\\":\\\"░\\\",\\\"blk34\\\":\\\"▓\\\",\\\"block\\\":\\\"█\\\",\\\"bne\\\":\\\"=⃥\\\",\\\"bnequiv\\\":\\\"≡⃥\\\",\\\"bNot\\\":\\\"⫭\\\",\\\"bnot\\\":\\\"⌐\\\",\\\"Bopf\\\":\\\"𝔹\\\",\\\"bopf\\\":\\\"𝕓\\\",\\\"bot\\\":\\\"⊥\\\",\\\"bottom\\\":\\\"⊥\\\",\\\"bowtie\\\":\\\"⋈\\\",\\\"boxbox\\\":\\\"⧉\\\",\\\"boxdl\\\":\\\"┐\\\",\\\"boxdL\\\":\\\"╕\\\",\\\"boxDl\\\":\\\"╖\\\",\\\"boxDL\\\":\\\"╗\\\",\\\"boxdr\\\":\\\"┌\\\",\\\"boxdR\\\":\\\"╒\\\",\\\"boxDr\\\":\\\"╓\\\",\\\"boxDR\\\":\\\"╔\\\",\\\"boxh\\\":\\\"─\\\",\\\"boxH\\\":\\\"═\\\",\\\"boxhd\\\":\\\"┬\\\",\\\"boxHd\\\":\\\"╤\\\",\\\"boxhD\\\":\\\"╥\\\",\\\"boxHD\\\":\\\"╦\\\",\\\"boxhu\\\":\\\"┴\\\",\\\"boxHu\\\":\\\"╧\\\",\\\"boxhU\\\":\\\"╨\\\",\\\"boxHU\\\":\\\"╩\\\",\\\"boxminus\\\":\\\"⊟\\\",\\\"boxplus\\\":\\\"⊞\\\",\\\"boxtimes\\\":\\\"⊠\\\",\\\"boxul\\\":\\\"┘\\\",\\\"boxuL\\\":\\\"╛\\\",\\\"boxUl\\\":\\\"╜\\\",\\\"boxUL\\\":\\\"╝\\\",\\\"boxur\\\":\\\"└\\\",\\\"boxuR\\\":\\\"╘\\\",\\\"boxUr\\\":\\\"╙\\\",\\\"boxUR\\\":\\\"╚\\\",\\\"boxv\\\":\\\"│\\\",\\\"boxV\\\":\\\"║\\\",\\\"boxvh\\\":\\\"┼\\\",\\\"boxvH\\\":\\\"╪\\\",\\\"boxVh\\\":\\\"╫\\\",\\\"boxVH\\\":\\\"╬\\\",\\\"boxvl\\\":\\\"┤\\\",\\\"boxvL\\\":\\\"╡\\\",\\\"boxVl\\\":\\\"╢\\\",\\\"boxVL\\\":\\\"╣\\\",\\\"boxvr\\\":\\\"├\\\",\\\"boxvR\\\":\\\"╞\\\",\\\"boxVr\\\":\\\"╟\\\",\\\"boxVR\\\":\\\"╠\\\",\\\"bprime\\\":\\\"‵\\\",\\\"breve\\\":\\\"˘\\\",\\\"Breve\\\":\\\"˘\\\",\\\"brvbar\\\":\\\"¦\\\",\\\"bscr\\\":\\\"𝒷\\\",\\\"Bscr\\\":\\\"ℬ\\\",\\\"bsemi\\\":\\\"⁏\\\",\\\"bsim\\\":\\\"∽\\\",\\\"bsime\\\":\\\"⋍\\\",\\\"bsolb\\\":\\\"⧅\\\",\\\"bsol\\\":\\\"\\\\\\\\\\\",\\\"bsolhsub\\\":\\\"⟈\\\",\\\"bull\\\":\\\"•\\\",\\\"bullet\\\":\\\"•\\\",\\\"bump\\\":\\\"≎\\\",\\\"bumpE\\\":\\\"⪮\\\",\\\"bumpe\\\":\\\"≏\\\",\\\"Bumpeq\\\":\\\"≎\\\",\\\"bumpeq\\\":\\\"≏\\\",\\\"Cacute\\\":\\\"Ć\\\",\\\"cacute\\\":\\\"ć\\\",\\\"capand\\\":\\\"⩄\\\",\\\"capbrcup\\\":\\\"⩉\\\",\\\"capcap\\\":\\\"⩋\\\",\\\"cap\\\":\\\"∩\\\",\\\"Cap\\\":\\\"⋒\\\",\\\"capcup\\\":\\\"⩇\\\",\\\"capdot\\\":\\\"⩀\\\",\\\"CapitalDifferentialD\\\":\\\"ⅅ\\\",\\\"caps\\\":\\\"∩︀\\\",\\\"caret\\\":\\\"⁁\\\",\\\"caron\\\":\\\"ˇ\\\",\\\"Cayleys\\\":\\\"ℭ\\\",\\\"ccaps\\\":\\\"⩍\\\",\\\"Ccaron\\\":\\\"Č\\\",\\\"ccaron\\\":\\\"č\\\",\\\"Ccedil\\\":\\\"Ç\\\",\\\"ccedil\\\":\\\"ç\\\",\\\"Ccirc\\\":\\\"Ĉ\\\",\\\"ccirc\\\":\\\"ĉ\\\",\\\"Cconint\\\":\\\"∰\\\",\\\"ccups\\\":\\\"⩌\\\",\\\"ccupssm\\\":\\\"⩐\\\",\\\"Cdot\\\":\\\"Ċ\\\",\\\"cdot\\\":\\\"ċ\\\",\\\"cedil\\\":\\\"¸\\\",\\\"Cedilla\\\":\\\"¸\\\",\\\"cemptyv\\\":\\\"⦲\\\",\\\"cent\\\":\\\"¢\\\",\\\"centerdot\\\":\\\"·\\\",\\\"CenterDot\\\":\\\"·\\\",\\\"cfr\\\":\\\"𝔠\\\",\\\"Cfr\\\":\\\"ℭ\\\",\\\"CHcy\\\":\\\"Ч\\\",\\\"chcy\\\":\\\"ч\\\",\\\"check\\\":\\\"✓\\\",\\\"checkmark\\\":\\\"✓\\\",\\\"Chi\\\":\\\"Χ\\\",\\\"chi\\\":\\\"χ\\\",\\\"circ\\\":\\\"ˆ\\\",\\\"circeq\\\":\\\"≗\\\",\\\"circlearrowleft\\\":\\\"↺\\\",\\\"circlearrowright\\\":\\\"↻\\\",\\\"circledast\\\":\\\"⊛\\\",\\\"circledcirc\\\":\\\"⊚\\\",\\\"circleddash\\\":\\\"⊝\\\",\\\"CircleDot\\\":\\\"⊙\\\",\\\"circledR\\\":\\\"®\\\",\\\"circledS\\\":\\\"Ⓢ\\\",\\\"CircleMinus\\\":\\\"⊖\\\",\\\"CirclePlus\\\":\\\"⊕\\\",\\\"CircleTimes\\\":\\\"⊗\\\",\\\"cir\\\":\\\"○\\\",\\\"cirE\\\":\\\"⧃\\\",\\\"cire\\\":\\\"≗\\\",\\\"cirfnint\\\":\\\"⨐\\\",\\\"cirmid\\\":\\\"⫯\\\",\\\"cirscir\\\":\\\"⧂\\\",\\\"ClockwiseContourIntegral\\\":\\\"∲\\\",\\\"CloseCurlyDoubleQuote\\\":\\\"”\\\",\\\"CloseCurlyQuote\\\":\\\"’\\\",\\\"clubs\\\":\\\"♣\\\",\\\"clubsuit\\\":\\\"♣\\\",\\\"colon\\\":\\\":\\\",\\\"Colon\\\":\\\"∷\\\",\\\"Colone\\\":\\\"⩴\\\",\\\"colone\\\":\\\"≔\\\",\\\"coloneq\\\":\\\"≔\\\",\\\"comma\\\":\\\",\\\",\\\"commat\\\":\\\"@\\\",\\\"comp\\\":\\\"∁\\\",\\\"compfn\\\":\\\"∘\\\",\\\"complement\\\":\\\"∁\\\",\\\"complexes\\\":\\\"ℂ\\\",\\\"cong\\\":\\\"≅\\\",\\\"congdot\\\":\\\"⩭\\\",\\\"Congruent\\\":\\\"≡\\\",\\\"conint\\\":\\\"∮\\\",\\\"Conint\\\":\\\"∯\\\",\\\"ContourIntegral\\\":\\\"∮\\\",\\\"copf\\\":\\\"𝕔\\\",\\\"Copf\\\":\\\"ℂ\\\",\\\"coprod\\\":\\\"∐\\\",\\\"Coproduct\\\":\\\"∐\\\",\\\"copy\\\":\\\"©\\\",\\\"COPY\\\":\\\"©\\\",\\\"copysr\\\":\\\"℗\\\",\\\"CounterClockwiseContourIntegral\\\":\\\"∳\\\",\\\"crarr\\\":\\\"↵\\\",\\\"cross\\\":\\\"✗\\\",\\\"Cross\\\":\\\"⨯\\\",\\\"Cscr\\\":\\\"𝒞\\\",\\\"cscr\\\":\\\"𝒸\\\",\\\"csub\\\":\\\"⫏\\\",\\\"csube\\\":\\\"⫑\\\",\\\"csup\\\":\\\"⫐\\\",\\\"csupe\\\":\\\"⫒\\\",\\\"ctdot\\\":\\\"⋯\\\",\\\"cudarrl\\\":\\\"⤸\\\",\\\"cudarrr\\\":\\\"⤵\\\",\\\"cuepr\\\":\\\"⋞\\\",\\\"cuesc\\\":\\\"⋟\\\",\\\"cularr\\\":\\\"↶\\\",\\\"cularrp\\\":\\\"⤽\\\",\\\"cupbrcap\\\":\\\"⩈\\\",\\\"cupcap\\\":\\\"⩆\\\",\\\"CupCap\\\":\\\"≍\\\",\\\"cup\\\":\\\"∪\\\",\\\"Cup\\\":\\\"⋓\\\",\\\"cupcup\\\":\\\"⩊\\\",\\\"cupdot\\\":\\\"⊍\\\",\\\"cupor\\\":\\\"⩅\\\",\\\"cups\\\":\\\"∪︀\\\",\\\"curarr\\\":\\\"↷\\\",\\\"curarrm\\\":\\\"⤼\\\",\\\"curlyeqprec\\\":\\\"⋞\\\",\\\"curlyeqsucc\\\":\\\"⋟\\\",\\\"curlyvee\\\":\\\"⋎\\\",\\\"curlywedge\\\":\\\"⋏\\\",\\\"curren\\\":\\\"¤\\\",\\\"curvearrowleft\\\":\\\"↶\\\",\\\"curvearrowright\\\":\\\"↷\\\",\\\"cuvee\\\":\\\"⋎\\\",\\\"cuwed\\\":\\\"⋏\\\",\\\"cwconint\\\":\\\"∲\\\",\\\"cwint\\\":\\\"∱\\\",\\\"cylcty\\\":\\\"⌭\\\",\\\"dagger\\\":\\\"†\\\",\\\"Dagger\\\":\\\"‡\\\",\\\"daleth\\\":\\\"ℸ\\\",\\\"darr\\\":\\\"↓\\\",\\\"Darr\\\":\\\"↡\\\",\\\"dArr\\\":\\\"⇓\\\",\\\"dash\\\":\\\"‐\\\",\\\"Dashv\\\":\\\"⫤\\\",\\\"dashv\\\":\\\"⊣\\\",\\\"dbkarow\\\":\\\"⤏\\\",\\\"dblac\\\":\\\"˝\\\",\\\"Dcaron\\\":\\\"Ď\\\",\\\"dcaron\\\":\\\"ď\\\",\\\"Dcy\\\":\\\"Д\\\",\\\"dcy\\\":\\\"д\\\",\\\"ddagger\\\":\\\"‡\\\",\\\"ddarr\\\":\\\"⇊\\\",\\\"DD\\\":\\\"ⅅ\\\",\\\"dd\\\":\\\"ⅆ\\\",\\\"DDotrahd\\\":\\\"⤑\\\",\\\"ddotseq\\\":\\\"⩷\\\",\\\"deg\\\":\\\"°\\\",\\\"Del\\\":\\\"∇\\\",\\\"Delta\\\":\\\"Δ\\\",\\\"delta\\\":\\\"δ\\\",\\\"demptyv\\\":\\\"⦱\\\",\\\"dfisht\\\":\\\"⥿\\\",\\\"Dfr\\\":\\\"𝔇\\\",\\\"dfr\\\":\\\"𝔡\\\",\\\"dHar\\\":\\\"⥥\\\",\\\"dharl\\\":\\\"⇃\\\",\\\"dharr\\\":\\\"⇂\\\",\\\"DiacriticalAcute\\\":\\\"´\\\",\\\"DiacriticalDot\\\":\\\"˙\\\",\\\"DiacriticalDoubleAcute\\\":\\\"˝\\\",\\\"DiacriticalGrave\\\":\\\"`\\\",\\\"DiacriticalTilde\\\":\\\"˜\\\",\\\"diam\\\":\\\"⋄\\\",\\\"diamond\\\":\\\"⋄\\\",\\\"Diamond\\\":\\\"⋄\\\",\\\"diamondsuit\\\":\\\"♦\\\",\\\"diams\\\":\\\"♦\\\",\\\"die\\\":\\\"¨\\\",\\\"DifferentialD\\\":\\\"ⅆ\\\",\\\"digamma\\\":\\\"ϝ\\\",\\\"disin\\\":\\\"⋲\\\",\\\"div\\\":\\\"÷\\\",\\\"divide\\\":\\\"÷\\\",\\\"divideontimes\\\":\\\"⋇\\\",\\\"divonx\\\":\\\"⋇\\\",\\\"DJcy\\\":\\\"Ђ\\\",\\\"djcy\\\":\\\"ђ\\\",\\\"dlcorn\\\":\\\"⌞\\\",\\\"dlcrop\\\":\\\"⌍\\\",\\\"dollar\\\":\\\"$\\\",\\\"Dopf\\\":\\\"𝔻\\\",\\\"dopf\\\":\\\"𝕕\\\",\\\"Dot\\\":\\\"¨\\\",\\\"dot\\\":\\\"˙\\\",\\\"DotDot\\\":\\\"⃜\\\",\\\"doteq\\\":\\\"≐\\\",\\\"doteqdot\\\":\\\"≑\\\",\\\"DotEqual\\\":\\\"≐\\\",\\\"dotminus\\\":\\\"∸\\\",\\\"dotplus\\\":\\\"∔\\\",\\\"dotsquare\\\":\\\"⊡\\\",\\\"doublebarwedge\\\":\\\"⌆\\\",\\\"DoubleContourIntegral\\\":\\\"∯\\\",\\\"DoubleDot\\\":\\\"¨\\\",\\\"DoubleDownArrow\\\":\\\"⇓\\\",\\\"DoubleLeftArrow\\\":\\\"⇐\\\",\\\"DoubleLeftRightArrow\\\":\\\"⇔\\\",\\\"DoubleLeftTee\\\":\\\"⫤\\\",\\\"DoubleLongLeftArrow\\\":\\\"⟸\\\",\\\"DoubleLongLeftRightArrow\\\":\\\"⟺\\\",\\\"DoubleLongRightArrow\\\":\\\"⟹\\\",\\\"DoubleRightArrow\\\":\\\"⇒\\\",\\\"DoubleRightTee\\\":\\\"⊨\\\",\\\"DoubleUpArrow\\\":\\\"⇑\\\",\\\"DoubleUpDownArrow\\\":\\\"⇕\\\",\\\"DoubleVerticalBar\\\":\\\"∥\\\",\\\"DownArrowBar\\\":\\\"⤓\\\",\\\"downarrow\\\":\\\"↓\\\",\\\"DownArrow\\\":\\\"↓\\\",\\\"Downarrow\\\":\\\"⇓\\\",\\\"DownArrowUpArrow\\\":\\\"⇵\\\",\\\"DownBreve\\\":\\\"̑\\\",\\\"downdownarrows\\\":\\\"⇊\\\",\\\"downharpoonleft\\\":\\\"⇃\\\",\\\"downharpoonright\\\":\\\"⇂\\\",\\\"DownLeftRightVector\\\":\\\"⥐\\\",\\\"DownLeftTeeVector\\\":\\\"⥞\\\",\\\"DownLeftVectorBar\\\":\\\"⥖\\\",\\\"DownLeftVector\\\":\\\"↽\\\",\\\"DownRightTeeVector\\\":\\\"⥟\\\",\\\"DownRightVectorBar\\\":\\\"⥗\\\",\\\"DownRightVector\\\":\\\"⇁\\\",\\\"DownTeeArrow\\\":\\\"↧\\\",\\\"DownTee\\\":\\\"⊤\\\",\\\"drbkarow\\\":\\\"⤐\\\",\\\"drcorn\\\":\\\"⌟\\\",\\\"drcrop\\\":\\\"⌌\\\",\\\"Dscr\\\":\\\"𝒟\\\",\\\"dscr\\\":\\\"𝒹\\\",\\\"DScy\\\":\\\"Ѕ\\\",\\\"dscy\\\":\\\"ѕ\\\",\\\"dsol\\\":\\\"⧶\\\",\\\"Dstrok\\\":\\\"Đ\\\",\\\"dstrok\\\":\\\"đ\\\",\\\"dtdot\\\":\\\"⋱\\\",\\\"dtri\\\":\\\"▿\\\",\\\"dtrif\\\":\\\"▾\\\",\\\"duarr\\\":\\\"⇵\\\",\\\"duhar\\\":\\\"⥯\\\",\\\"dwangle\\\":\\\"⦦\\\",\\\"DZcy\\\":\\\"Џ\\\",\\\"dzcy\\\":\\\"џ\\\",\\\"dzigrarr\\\":\\\"⟿\\\",\\\"Eacute\\\":\\\"É\\\",\\\"eacute\\\":\\\"é\\\",\\\"easter\\\":\\\"⩮\\\",\\\"Ecaron\\\":\\\"Ě\\\",\\\"ecaron\\\":\\\"ě\\\",\\\"Ecirc\\\":\\\"Ê\\\",\\\"ecirc\\\":\\\"ê\\\",\\\"ecir\\\":\\\"≖\\\",\\\"ecolon\\\":\\\"≕\\\",\\\"Ecy\\\":\\\"Э\\\",\\\"ecy\\\":\\\"э\\\",\\\"eDDot\\\":\\\"⩷\\\",\\\"Edot\\\":\\\"Ė\\\",\\\"edot\\\":\\\"ė\\\",\\\"eDot\\\":\\\"≑\\\",\\\"ee\\\":\\\"ⅇ\\\",\\\"efDot\\\":\\\"≒\\\",\\\"Efr\\\":\\\"𝔈\\\",\\\"efr\\\":\\\"𝔢\\\",\\\"eg\\\":\\\"⪚\\\",\\\"Egrave\\\":\\\"È\\\",\\\"egrave\\\":\\\"è\\\",\\\"egs\\\":\\\"⪖\\\",\\\"egsdot\\\":\\\"⪘\\\",\\\"el\\\":\\\"⪙\\\",\\\"Element\\\":\\\"∈\\\",\\\"elinters\\\":\\\"⏧\\\",\\\"ell\\\":\\\"ℓ\\\",\\\"els\\\":\\\"⪕\\\",\\\"elsdot\\\":\\\"⪗\\\",\\\"Emacr\\\":\\\"Ē\\\",\\\"emacr\\\":\\\"ē\\\",\\\"empty\\\":\\\"∅\\\",\\\"emptyset\\\":\\\"∅\\\",\\\"EmptySmallSquare\\\":\\\"◻\\\",\\\"emptyv\\\":\\\"∅\\\",\\\"EmptyVerySmallSquare\\\":\\\"▫\\\",\\\"emsp13\\\":\\\" \\\",\\\"emsp14\\\":\\\" \\\",\\\"emsp\\\":\\\" \\\",\\\"ENG\\\":\\\"Ŋ\\\",\\\"eng\\\":\\\"ŋ\\\",\\\"ensp\\\":\\\" \\\",\\\"Eogon\\\":\\\"Ę\\\",\\\"eogon\\\":\\\"ę\\\",\\\"Eopf\\\":\\\"𝔼\\\",\\\"eopf\\\":\\\"𝕖\\\",\\\"epar\\\":\\\"⋕\\\",\\\"eparsl\\\":\\\"⧣\\\",\\\"eplus\\\":\\\"⩱\\\",\\\"epsi\\\":\\\"ε\\\",\\\"Epsilon\\\":\\\"Ε\\\",\\\"epsilon\\\":\\\"ε\\\",\\\"epsiv\\\":\\\"ϵ\\\",\\\"eqcirc\\\":\\\"≖\\\",\\\"eqcolon\\\":\\\"≕\\\",\\\"eqsim\\\":\\\"≂\\\",\\\"eqslantgtr\\\":\\\"⪖\\\",\\\"eqslantless\\\":\\\"⪕\\\",\\\"Equal\\\":\\\"⩵\\\",\\\"equals\\\":\\\"=\\\",\\\"EqualTilde\\\":\\\"≂\\\",\\\"equest\\\":\\\"≟\\\",\\\"Equilibrium\\\":\\\"⇌\\\",\\\"equiv\\\":\\\"≡\\\",\\\"equivDD\\\":\\\"⩸\\\",\\\"eqvparsl\\\":\\\"⧥\\\",\\\"erarr\\\":\\\"⥱\\\",\\\"erDot\\\":\\\"≓\\\",\\\"escr\\\":\\\"ℯ\\\",\\\"Escr\\\":\\\"ℰ\\\",\\\"esdot\\\":\\\"≐\\\",\\\"Esim\\\":\\\"⩳\\\",\\\"esim\\\":\\\"≂\\\",\\\"Eta\\\":\\\"Η\\\",\\\"eta\\\":\\\"η\\\",\\\"ETH\\\":\\\"Ð\\\",\\\"eth\\\":\\\"ð\\\",\\\"Euml\\\":\\\"Ë\\\",\\\"euml\\\":\\\"ë\\\",\\\"euro\\\":\\\"€\\\",\\\"excl\\\":\\\"!\\\",\\\"exist\\\":\\\"∃\\\",\\\"Exists\\\":\\\"∃\\\",\\\"expectation\\\":\\\"ℰ\\\",\\\"exponentiale\\\":\\\"ⅇ\\\",\\\"ExponentialE\\\":\\\"ⅇ\\\",\\\"fallingdotseq\\\":\\\"≒\\\",\\\"Fcy\\\":\\\"Ф\\\",\\\"fcy\\\":\\\"ф\\\",\\\"female\\\":\\\"♀\\\",\\\"ffilig\\\":\\\"ffi\\\",\\\"fflig\\\":\\\"ff\\\",\\\"ffllig\\\":\\\"ffl\\\",\\\"Ffr\\\":\\\"𝔉\\\",\\\"ffr\\\":\\\"𝔣\\\",\\\"filig\\\":\\\"fi\\\",\\\"FilledSmallSquare\\\":\\\"◼\\\",\\\"FilledVerySmallSquare\\\":\\\"▪\\\",\\\"fjlig\\\":\\\"fj\\\",\\\"flat\\\":\\\"♭\\\",\\\"fllig\\\":\\\"fl\\\",\\\"fltns\\\":\\\"▱\\\",\\\"fnof\\\":\\\"ƒ\\\",\\\"Fopf\\\":\\\"𝔽\\\",\\\"fopf\\\":\\\"𝕗\\\",\\\"forall\\\":\\\"∀\\\",\\\"ForAll\\\":\\\"∀\\\",\\\"fork\\\":\\\"⋔\\\",\\\"forkv\\\":\\\"⫙\\\",\\\"Fouriertrf\\\":\\\"ℱ\\\",\\\"fpartint\\\":\\\"⨍\\\",\\\"frac12\\\":\\\"½\\\",\\\"frac13\\\":\\\"⅓\\\",\\\"frac14\\\":\\\"¼\\\",\\\"frac15\\\":\\\"⅕\\\",\\\"frac16\\\":\\\"⅙\\\",\\\"frac18\\\":\\\"⅛\\\",\\\"frac23\\\":\\\"⅔\\\",\\\"frac25\\\":\\\"⅖\\\",\\\"frac34\\\":\\\"¾\\\",\\\"frac35\\\":\\\"⅗\\\",\\\"frac38\\\":\\\"⅜\\\",\\\"frac45\\\":\\\"⅘\\\",\\\"frac56\\\":\\\"⅚\\\",\\\"frac58\\\":\\\"⅝\\\",\\\"frac78\\\":\\\"⅞\\\",\\\"frasl\\\":\\\"⁄\\\",\\\"frown\\\":\\\"⌢\\\",\\\"fscr\\\":\\\"𝒻\\\",\\\"Fscr\\\":\\\"ℱ\\\",\\\"gacute\\\":\\\"ǵ\\\",\\\"Gamma\\\":\\\"Γ\\\",\\\"gamma\\\":\\\"γ\\\",\\\"Gammad\\\":\\\"Ϝ\\\",\\\"gammad\\\":\\\"ϝ\\\",\\\"gap\\\":\\\"⪆\\\",\\\"Gbreve\\\":\\\"Ğ\\\",\\\"gbreve\\\":\\\"ğ\\\",\\\"Gcedil\\\":\\\"Ģ\\\",\\\"Gcirc\\\":\\\"Ĝ\\\",\\\"gcirc\\\":\\\"ĝ\\\",\\\"Gcy\\\":\\\"Г\\\",\\\"gcy\\\":\\\"г\\\",\\\"Gdot\\\":\\\"Ġ\\\",\\\"gdot\\\":\\\"ġ\\\",\\\"ge\\\":\\\"≥\\\",\\\"gE\\\":\\\"≧\\\",\\\"gEl\\\":\\\"⪌\\\",\\\"gel\\\":\\\"⋛\\\",\\\"geq\\\":\\\"≥\\\",\\\"geqq\\\":\\\"≧\\\",\\\"geqslant\\\":\\\"⩾\\\",\\\"gescc\\\":\\\"⪩\\\",\\\"ges\\\":\\\"⩾\\\",\\\"gesdot\\\":\\\"⪀\\\",\\\"gesdoto\\\":\\\"⪂\\\",\\\"gesdotol\\\":\\\"⪄\\\",\\\"gesl\\\":\\\"⋛︀\\\",\\\"gesles\\\":\\\"⪔\\\",\\\"Gfr\\\":\\\"𝔊\\\",\\\"gfr\\\":\\\"𝔤\\\",\\\"gg\\\":\\\"≫\\\",\\\"Gg\\\":\\\"⋙\\\",\\\"ggg\\\":\\\"⋙\\\",\\\"gimel\\\":\\\"ℷ\\\",\\\"GJcy\\\":\\\"Ѓ\\\",\\\"gjcy\\\":\\\"ѓ\\\",\\\"gla\\\":\\\"⪥\\\",\\\"gl\\\":\\\"≷\\\",\\\"glE\\\":\\\"⪒\\\",\\\"glj\\\":\\\"⪤\\\",\\\"gnap\\\":\\\"⪊\\\",\\\"gnapprox\\\":\\\"⪊\\\",\\\"gne\\\":\\\"⪈\\\",\\\"gnE\\\":\\\"≩\\\",\\\"gneq\\\":\\\"⪈\\\",\\\"gneqq\\\":\\\"≩\\\",\\\"gnsim\\\":\\\"⋧\\\",\\\"Gopf\\\":\\\"𝔾\\\",\\\"gopf\\\":\\\"𝕘\\\",\\\"grave\\\":\\\"`\\\",\\\"GreaterEqual\\\":\\\"≥\\\",\\\"GreaterEqualLess\\\":\\\"⋛\\\",\\\"GreaterFullEqual\\\":\\\"≧\\\",\\\"GreaterGreater\\\":\\\"⪢\\\",\\\"GreaterLess\\\":\\\"≷\\\",\\\"GreaterSlantEqual\\\":\\\"⩾\\\",\\\"GreaterTilde\\\":\\\"≳\\\",\\\"Gscr\\\":\\\"𝒢\\\",\\\"gscr\\\":\\\"ℊ\\\",\\\"gsim\\\":\\\"≳\\\",\\\"gsime\\\":\\\"⪎\\\",\\\"gsiml\\\":\\\"⪐\\\",\\\"gtcc\\\":\\\"⪧\\\",\\\"gtcir\\\":\\\"⩺\\\",\\\"gt\\\":\\\">\\\",\\\"GT\\\":\\\">\\\",\\\"Gt\\\":\\\"≫\\\",\\\"gtdot\\\":\\\"⋗\\\",\\\"gtlPar\\\":\\\"⦕\\\",\\\"gtquest\\\":\\\"⩼\\\",\\\"gtrapprox\\\":\\\"⪆\\\",\\\"gtrarr\\\":\\\"⥸\\\",\\\"gtrdot\\\":\\\"⋗\\\",\\\"gtreqless\\\":\\\"⋛\\\",\\\"gtreqqless\\\":\\\"⪌\\\",\\\"gtrless\\\":\\\"≷\\\",\\\"gtrsim\\\":\\\"≳\\\",\\\"gvertneqq\\\":\\\"≩︀\\\",\\\"gvnE\\\":\\\"≩︀\\\",\\\"Hacek\\\":\\\"ˇ\\\",\\\"hairsp\\\":\\\" \\\",\\\"half\\\":\\\"½\\\",\\\"hamilt\\\":\\\"ℋ\\\",\\\"HARDcy\\\":\\\"Ъ\\\",\\\"hardcy\\\":\\\"ъ\\\",\\\"harrcir\\\":\\\"⥈\\\",\\\"harr\\\":\\\"↔\\\",\\\"hArr\\\":\\\"⇔\\\",\\\"harrw\\\":\\\"↭\\\",\\\"Hat\\\":\\\"^\\\",\\\"hbar\\\":\\\"ℏ\\\",\\\"Hcirc\\\":\\\"Ĥ\\\",\\\"hcirc\\\":\\\"ĥ\\\",\\\"hearts\\\":\\\"♥\\\",\\\"heartsuit\\\":\\\"♥\\\",\\\"hellip\\\":\\\"…\\\",\\\"hercon\\\":\\\"⊹\\\",\\\"hfr\\\":\\\"𝔥\\\",\\\"Hfr\\\":\\\"ℌ\\\",\\\"HilbertSpace\\\":\\\"ℋ\\\",\\\"hksearow\\\":\\\"⤥\\\",\\\"hkswarow\\\":\\\"⤦\\\",\\\"hoarr\\\":\\\"⇿\\\",\\\"homtht\\\":\\\"∻\\\",\\\"hookleftarrow\\\":\\\"↩\\\",\\\"hookrightarrow\\\":\\\"↪\\\",\\\"hopf\\\":\\\"𝕙\\\",\\\"Hopf\\\":\\\"ℍ\\\",\\\"horbar\\\":\\\"―\\\",\\\"HorizontalLine\\\":\\\"─\\\",\\\"hscr\\\":\\\"𝒽\\\",\\\"Hscr\\\":\\\"ℋ\\\",\\\"hslash\\\":\\\"ℏ\\\",\\\"Hstrok\\\":\\\"Ħ\\\",\\\"hstrok\\\":\\\"ħ\\\",\\\"HumpDownHump\\\":\\\"≎\\\",\\\"HumpEqual\\\":\\\"≏\\\",\\\"hybull\\\":\\\"⁃\\\",\\\"hyphen\\\":\\\"‐\\\",\\\"Iacute\\\":\\\"Í\\\",\\\"iacute\\\":\\\"í\\\",\\\"ic\\\":\\\"⁣\\\",\\\"Icirc\\\":\\\"Î\\\",\\\"icirc\\\":\\\"î\\\",\\\"Icy\\\":\\\"И\\\",\\\"icy\\\":\\\"и\\\",\\\"Idot\\\":\\\"İ\\\",\\\"IEcy\\\":\\\"Е\\\",\\\"iecy\\\":\\\"е\\\",\\\"iexcl\\\":\\\"¡\\\",\\\"iff\\\":\\\"⇔\\\",\\\"ifr\\\":\\\"𝔦\\\",\\\"Ifr\\\":\\\"ℑ\\\",\\\"Igrave\\\":\\\"Ì\\\",\\\"igrave\\\":\\\"ì\\\",\\\"ii\\\":\\\"ⅈ\\\",\\\"iiiint\\\":\\\"⨌\\\",\\\"iiint\\\":\\\"∭\\\",\\\"iinfin\\\":\\\"⧜\\\",\\\"iiota\\\":\\\"℩\\\",\\\"IJlig\\\":\\\"IJ\\\",\\\"ijlig\\\":\\\"ij\\\",\\\"Imacr\\\":\\\"Ī\\\",\\\"imacr\\\":\\\"ī\\\",\\\"image\\\":\\\"ℑ\\\",\\\"ImaginaryI\\\":\\\"ⅈ\\\",\\\"imagline\\\":\\\"ℐ\\\",\\\"imagpart\\\":\\\"ℑ\\\",\\\"imath\\\":\\\"ı\\\",\\\"Im\\\":\\\"ℑ\\\",\\\"imof\\\":\\\"⊷\\\",\\\"imped\\\":\\\"Ƶ\\\",\\\"Implies\\\":\\\"⇒\\\",\\\"incare\\\":\\\"℅\\\",\\\"in\\\":\\\"∈\\\",\\\"infin\\\":\\\"∞\\\",\\\"infintie\\\":\\\"⧝\\\",\\\"inodot\\\":\\\"ı\\\",\\\"intcal\\\":\\\"⊺\\\",\\\"int\\\":\\\"∫\\\",\\\"Int\\\":\\\"∬\\\",\\\"integers\\\":\\\"ℤ\\\",\\\"Integral\\\":\\\"∫\\\",\\\"intercal\\\":\\\"⊺\\\",\\\"Intersection\\\":\\\"⋂\\\",\\\"intlarhk\\\":\\\"⨗\\\",\\\"intprod\\\":\\\"⨼\\\",\\\"InvisibleComma\\\":\\\"⁣\\\",\\\"InvisibleTimes\\\":\\\"⁢\\\",\\\"IOcy\\\":\\\"Ё\\\",\\\"iocy\\\":\\\"ё\\\",\\\"Iogon\\\":\\\"Į\\\",\\\"iogon\\\":\\\"į\\\",\\\"Iopf\\\":\\\"𝕀\\\",\\\"iopf\\\":\\\"𝕚\\\",\\\"Iota\\\":\\\"Ι\\\",\\\"iota\\\":\\\"ι\\\",\\\"iprod\\\":\\\"⨼\\\",\\\"iquest\\\":\\\"¿\\\",\\\"iscr\\\":\\\"𝒾\\\",\\\"Iscr\\\":\\\"ℐ\\\",\\\"isin\\\":\\\"∈\\\",\\\"isindot\\\":\\\"⋵\\\",\\\"isinE\\\":\\\"⋹\\\",\\\"isins\\\":\\\"⋴\\\",\\\"isinsv\\\":\\\"⋳\\\",\\\"isinv\\\":\\\"∈\\\",\\\"it\\\":\\\"⁢\\\",\\\"Itilde\\\":\\\"Ĩ\\\",\\\"itilde\\\":\\\"ĩ\\\",\\\"Iukcy\\\":\\\"І\\\",\\\"iukcy\\\":\\\"і\\\",\\\"Iuml\\\":\\\"Ï\\\",\\\"iuml\\\":\\\"ï\\\",\\\"Jcirc\\\":\\\"Ĵ\\\",\\\"jcirc\\\":\\\"ĵ\\\",\\\"Jcy\\\":\\\"Й\\\",\\\"jcy\\\":\\\"й\\\",\\\"Jfr\\\":\\\"𝔍\\\",\\\"jfr\\\":\\\"𝔧\\\",\\\"jmath\\\":\\\"ȷ\\\",\\\"Jopf\\\":\\\"𝕁\\\",\\\"jopf\\\":\\\"𝕛\\\",\\\"Jscr\\\":\\\"𝒥\\\",\\\"jscr\\\":\\\"𝒿\\\",\\\"Jsercy\\\":\\\"Ј\\\",\\\"jsercy\\\":\\\"ј\\\",\\\"Jukcy\\\":\\\"Є\\\",\\\"jukcy\\\":\\\"є\\\",\\\"Kappa\\\":\\\"Κ\\\",\\\"kappa\\\":\\\"κ\\\",\\\"kappav\\\":\\\"ϰ\\\",\\\"Kcedil\\\":\\\"Ķ\\\",\\\"kcedil\\\":\\\"ķ\\\",\\\"Kcy\\\":\\\"К\\\",\\\"kcy\\\":\\\"к\\\",\\\"Kfr\\\":\\\"𝔎\\\",\\\"kfr\\\":\\\"𝔨\\\",\\\"kgreen\\\":\\\"ĸ\\\",\\\"KHcy\\\":\\\"Х\\\",\\\"khcy\\\":\\\"х\\\",\\\"KJcy\\\":\\\"Ќ\\\",\\\"kjcy\\\":\\\"ќ\\\",\\\"Kopf\\\":\\\"𝕂\\\",\\\"kopf\\\":\\\"𝕜\\\",\\\"Kscr\\\":\\\"𝒦\\\",\\\"kscr\\\":\\\"𝓀\\\",\\\"lAarr\\\":\\\"⇚\\\",\\\"Lacute\\\":\\\"Ĺ\\\",\\\"lacute\\\":\\\"ĺ\\\",\\\"laemptyv\\\":\\\"⦴\\\",\\\"lagran\\\":\\\"ℒ\\\",\\\"Lambda\\\":\\\"Λ\\\",\\\"lambda\\\":\\\"λ\\\",\\\"lang\\\":\\\"⟨\\\",\\\"Lang\\\":\\\"⟪\\\",\\\"langd\\\":\\\"⦑\\\",\\\"langle\\\":\\\"⟨\\\",\\\"lap\\\":\\\"⪅\\\",\\\"Laplacetrf\\\":\\\"ℒ\\\",\\\"laquo\\\":\\\"«\\\",\\\"larrb\\\":\\\"⇤\\\",\\\"larrbfs\\\":\\\"⤟\\\",\\\"larr\\\":\\\"←\\\",\\\"Larr\\\":\\\"↞\\\",\\\"lArr\\\":\\\"⇐\\\",\\\"larrfs\\\":\\\"⤝\\\",\\\"larrhk\\\":\\\"↩\\\",\\\"larrlp\\\":\\\"↫\\\",\\\"larrpl\\\":\\\"⤹\\\",\\\"larrsim\\\":\\\"⥳\\\",\\\"larrtl\\\":\\\"↢\\\",\\\"latail\\\":\\\"⤙\\\",\\\"lAtail\\\":\\\"⤛\\\",\\\"lat\\\":\\\"⪫\\\",\\\"late\\\":\\\"⪭\\\",\\\"lates\\\":\\\"⪭︀\\\",\\\"lbarr\\\":\\\"⤌\\\",\\\"lBarr\\\":\\\"⤎\\\",\\\"lbbrk\\\":\\\"❲\\\",\\\"lbrace\\\":\\\"{\\\",\\\"lbrack\\\":\\\"[\\\",\\\"lbrke\\\":\\\"⦋\\\",\\\"lbrksld\\\":\\\"⦏\\\",\\\"lbrkslu\\\":\\\"⦍\\\",\\\"Lcaron\\\":\\\"Ľ\\\",\\\"lcaron\\\":\\\"ľ\\\",\\\"Lcedil\\\":\\\"Ļ\\\",\\\"lcedil\\\":\\\"ļ\\\",\\\"lceil\\\":\\\"⌈\\\",\\\"lcub\\\":\\\"{\\\",\\\"Lcy\\\":\\\"Л\\\",\\\"lcy\\\":\\\"л\\\",\\\"ldca\\\":\\\"⤶\\\",\\\"ldquo\\\":\\\"“\\\",\\\"ldquor\\\":\\\"„\\\",\\\"ldrdhar\\\":\\\"⥧\\\",\\\"ldrushar\\\":\\\"⥋\\\",\\\"ldsh\\\":\\\"↲\\\",\\\"le\\\":\\\"≤\\\",\\\"lE\\\":\\\"≦\\\",\\\"LeftAngleBracket\\\":\\\"⟨\\\",\\\"LeftArrowBar\\\":\\\"⇤\\\",\\\"leftarrow\\\":\\\"←\\\",\\\"LeftArrow\\\":\\\"←\\\",\\\"Leftarrow\\\":\\\"⇐\\\",\\\"LeftArrowRightArrow\\\":\\\"⇆\\\",\\\"leftarrowtail\\\":\\\"↢\\\",\\\"LeftCeiling\\\":\\\"⌈\\\",\\\"LeftDoubleBracket\\\":\\\"⟦\\\",\\\"LeftDownTeeVector\\\":\\\"⥡\\\",\\\"LeftDownVectorBar\\\":\\\"⥙\\\",\\\"LeftDownVector\\\":\\\"⇃\\\",\\\"LeftFloor\\\":\\\"⌊\\\",\\\"leftharpoondown\\\":\\\"↽\\\",\\\"leftharpoonup\\\":\\\"↼\\\",\\\"leftleftarrows\\\":\\\"⇇\\\",\\\"leftrightarrow\\\":\\\"↔\\\",\\\"LeftRightArrow\\\":\\\"↔\\\",\\\"Leftrightarrow\\\":\\\"⇔\\\",\\\"leftrightarrows\\\":\\\"⇆\\\",\\\"leftrightharpoons\\\":\\\"⇋\\\",\\\"leftrightsquigarrow\\\":\\\"↭\\\",\\\"LeftRightVector\\\":\\\"⥎\\\",\\\"LeftTeeArrow\\\":\\\"↤\\\",\\\"LeftTee\\\":\\\"⊣\\\",\\\"LeftTeeVector\\\":\\\"⥚\\\",\\\"leftthreetimes\\\":\\\"⋋\\\",\\\"LeftTriangleBar\\\":\\\"⧏\\\",\\\"LeftTriangle\\\":\\\"⊲\\\",\\\"LeftTriangleEqual\\\":\\\"⊴\\\",\\\"LeftUpDownVector\\\":\\\"⥑\\\",\\\"LeftUpTeeVector\\\":\\\"⥠\\\",\\\"LeftUpVectorBar\\\":\\\"⥘\\\",\\\"LeftUpVector\\\":\\\"↿\\\",\\\"LeftVectorBar\\\":\\\"⥒\\\",\\\"LeftVector\\\":\\\"↼\\\",\\\"lEg\\\":\\\"⪋\\\",\\\"leg\\\":\\\"⋚\\\",\\\"leq\\\":\\\"≤\\\",\\\"leqq\\\":\\\"≦\\\",\\\"leqslant\\\":\\\"⩽\\\",\\\"lescc\\\":\\\"⪨\\\",\\\"les\\\":\\\"⩽\\\",\\\"lesdot\\\":\\\"⩿\\\",\\\"lesdoto\\\":\\\"⪁\\\",\\\"lesdotor\\\":\\\"⪃\\\",\\\"lesg\\\":\\\"⋚︀\\\",\\\"lesges\\\":\\\"⪓\\\",\\\"lessapprox\\\":\\\"⪅\\\",\\\"lessdot\\\":\\\"⋖\\\",\\\"lesseqgtr\\\":\\\"⋚\\\",\\\"lesseqqgtr\\\":\\\"⪋\\\",\\\"LessEqualGreater\\\":\\\"⋚\\\",\\\"LessFullEqual\\\":\\\"≦\\\",\\\"LessGreater\\\":\\\"≶\\\",\\\"lessgtr\\\":\\\"≶\\\",\\\"LessLess\\\":\\\"⪡\\\",\\\"lesssim\\\":\\\"≲\\\",\\\"LessSlantEqual\\\":\\\"⩽\\\",\\\"LessTilde\\\":\\\"≲\\\",\\\"lfisht\\\":\\\"⥼\\\",\\\"lfloor\\\":\\\"⌊\\\",\\\"Lfr\\\":\\\"𝔏\\\",\\\"lfr\\\":\\\"𝔩\\\",\\\"lg\\\":\\\"≶\\\",\\\"lgE\\\":\\\"⪑\\\",\\\"lHar\\\":\\\"⥢\\\",\\\"lhard\\\":\\\"↽\\\",\\\"lharu\\\":\\\"↼\\\",\\\"lharul\\\":\\\"⥪\\\",\\\"lhblk\\\":\\\"▄\\\",\\\"LJcy\\\":\\\"Љ\\\",\\\"ljcy\\\":\\\"љ\\\",\\\"llarr\\\":\\\"⇇\\\",\\\"ll\\\":\\\"≪\\\",\\\"Ll\\\":\\\"⋘\\\",\\\"llcorner\\\":\\\"⌞\\\",\\\"Lleftarrow\\\":\\\"⇚\\\",\\\"llhard\\\":\\\"⥫\\\",\\\"lltri\\\":\\\"◺\\\",\\\"Lmidot\\\":\\\"Ŀ\\\",\\\"lmidot\\\":\\\"ŀ\\\",\\\"lmoustache\\\":\\\"⎰\\\",\\\"lmoust\\\":\\\"⎰\\\",\\\"lnap\\\":\\\"⪉\\\",\\\"lnapprox\\\":\\\"⪉\\\",\\\"lne\\\":\\\"⪇\\\",\\\"lnE\\\":\\\"≨\\\",\\\"lneq\\\":\\\"⪇\\\",\\\"lneqq\\\":\\\"≨\\\",\\\"lnsim\\\":\\\"⋦\\\",\\\"loang\\\":\\\"⟬\\\",\\\"loarr\\\":\\\"⇽\\\",\\\"lobrk\\\":\\\"⟦\\\",\\\"longleftarrow\\\":\\\"⟵\\\",\\\"LongLeftArrow\\\":\\\"⟵\\\",\\\"Longleftarrow\\\":\\\"⟸\\\",\\\"longleftrightarrow\\\":\\\"⟷\\\",\\\"LongLeftRightArrow\\\":\\\"⟷\\\",\\\"Longleftrightarrow\\\":\\\"⟺\\\",\\\"longmapsto\\\":\\\"⟼\\\",\\\"longrightarrow\\\":\\\"⟶\\\",\\\"LongRightArrow\\\":\\\"⟶\\\",\\\"Longrightarrow\\\":\\\"⟹\\\",\\\"looparrowleft\\\":\\\"↫\\\",\\\"looparrowright\\\":\\\"↬\\\",\\\"lopar\\\":\\\"⦅\\\",\\\"Lopf\\\":\\\"𝕃\\\",\\\"lopf\\\":\\\"𝕝\\\",\\\"loplus\\\":\\\"⨭\\\",\\\"lotimes\\\":\\\"⨴\\\",\\\"lowast\\\":\\\"∗\\\",\\\"lowbar\\\":\\\"_\\\",\\\"LowerLeftArrow\\\":\\\"↙\\\",\\\"LowerRightArrow\\\":\\\"↘\\\",\\\"loz\\\":\\\"◊\\\",\\\"lozenge\\\":\\\"◊\\\",\\\"lozf\\\":\\\"⧫\\\",\\\"lpar\\\":\\\"(\\\",\\\"lparlt\\\":\\\"⦓\\\",\\\"lrarr\\\":\\\"⇆\\\",\\\"lrcorner\\\":\\\"⌟\\\",\\\"lrhar\\\":\\\"⇋\\\",\\\"lrhard\\\":\\\"⥭\\\",\\\"lrm\\\":\\\"‎\\\",\\\"lrtri\\\":\\\"⊿\\\",\\\"lsaquo\\\":\\\"‹\\\",\\\"lscr\\\":\\\"𝓁\\\",\\\"Lscr\\\":\\\"ℒ\\\",\\\"lsh\\\":\\\"↰\\\",\\\"Lsh\\\":\\\"↰\\\",\\\"lsim\\\":\\\"≲\\\",\\\"lsime\\\":\\\"⪍\\\",\\\"lsimg\\\":\\\"⪏\\\",\\\"lsqb\\\":\\\"[\\\",\\\"lsquo\\\":\\\"‘\\\",\\\"lsquor\\\":\\\"‚\\\",\\\"Lstrok\\\":\\\"Ł\\\",\\\"lstrok\\\":\\\"ł\\\",\\\"ltcc\\\":\\\"⪦\\\",\\\"ltcir\\\":\\\"⩹\\\",\\\"lt\\\":\\\"<\\\",\\\"LT\\\":\\\"<\\\",\\\"Lt\\\":\\\"≪\\\",\\\"ltdot\\\":\\\"⋖\\\",\\\"lthree\\\":\\\"⋋\\\",\\\"ltimes\\\":\\\"⋉\\\",\\\"ltlarr\\\":\\\"⥶\\\",\\\"ltquest\\\":\\\"⩻\\\",\\\"ltri\\\":\\\"◃\\\",\\\"ltrie\\\":\\\"⊴\\\",\\\"ltrif\\\":\\\"◂\\\",\\\"ltrPar\\\":\\\"⦖\\\",\\\"lurdshar\\\":\\\"⥊\\\",\\\"luruhar\\\":\\\"⥦\\\",\\\"lvertneqq\\\":\\\"≨︀\\\",\\\"lvnE\\\":\\\"≨︀\\\",\\\"macr\\\":\\\"¯\\\",\\\"male\\\":\\\"♂\\\",\\\"malt\\\":\\\"✠\\\",\\\"maltese\\\":\\\"✠\\\",\\\"Map\\\":\\\"⤅\\\",\\\"map\\\":\\\"↦\\\",\\\"mapsto\\\":\\\"↦\\\",\\\"mapstodown\\\":\\\"↧\\\",\\\"mapstoleft\\\":\\\"↤\\\",\\\"mapstoup\\\":\\\"↥\\\",\\\"marker\\\":\\\"▮\\\",\\\"mcomma\\\":\\\"⨩\\\",\\\"Mcy\\\":\\\"М\\\",\\\"mcy\\\":\\\"м\\\",\\\"mdash\\\":\\\"—\\\",\\\"mDDot\\\":\\\"∺\\\",\\\"measuredangle\\\":\\\"∡\\\",\\\"MediumSpace\\\":\\\" \\\",\\\"Mellintrf\\\":\\\"ℳ\\\",\\\"Mfr\\\":\\\"𝔐\\\",\\\"mfr\\\":\\\"𝔪\\\",\\\"mho\\\":\\\"℧\\\",\\\"micro\\\":\\\"µ\\\",\\\"midast\\\":\\\"*\\\",\\\"midcir\\\":\\\"⫰\\\",\\\"mid\\\":\\\"∣\\\",\\\"middot\\\":\\\"·\\\",\\\"minusb\\\":\\\"⊟\\\",\\\"minus\\\":\\\"−\\\",\\\"minusd\\\":\\\"∸\\\",\\\"minusdu\\\":\\\"⨪\\\",\\\"MinusPlus\\\":\\\"∓\\\",\\\"mlcp\\\":\\\"⫛\\\",\\\"mldr\\\":\\\"…\\\",\\\"mnplus\\\":\\\"∓\\\",\\\"models\\\":\\\"⊧\\\",\\\"Mopf\\\":\\\"𝕄\\\",\\\"mopf\\\":\\\"𝕞\\\",\\\"mp\\\":\\\"∓\\\",\\\"mscr\\\":\\\"𝓂\\\",\\\"Mscr\\\":\\\"ℳ\\\",\\\"mstpos\\\":\\\"∾\\\",\\\"Mu\\\":\\\"Μ\\\",\\\"mu\\\":\\\"μ\\\",\\\"multimap\\\":\\\"⊸\\\",\\\"mumap\\\":\\\"⊸\\\",\\\"nabla\\\":\\\"∇\\\",\\\"Nacute\\\":\\\"Ń\\\",\\\"nacute\\\":\\\"ń\\\",\\\"nang\\\":\\\"∠⃒\\\",\\\"nap\\\":\\\"≉\\\",\\\"napE\\\":\\\"⩰̸\\\",\\\"napid\\\":\\\"≋̸\\\",\\\"napos\\\":\\\"ʼn\\\",\\\"napprox\\\":\\\"≉\\\",\\\"natural\\\":\\\"♮\\\",\\\"naturals\\\":\\\"ℕ\\\",\\\"natur\\\":\\\"♮\\\",\\\"nbsp\\\":\\\" \\\",\\\"nbump\\\":\\\"≎̸\\\",\\\"nbumpe\\\":\\\"≏̸\\\",\\\"ncap\\\":\\\"⩃\\\",\\\"Ncaron\\\":\\\"Ň\\\",\\\"ncaron\\\":\\\"ň\\\",\\\"Ncedil\\\":\\\"Ņ\\\",\\\"ncedil\\\":\\\"ņ\\\",\\\"ncong\\\":\\\"≇\\\",\\\"ncongdot\\\":\\\"⩭̸\\\",\\\"ncup\\\":\\\"⩂\\\",\\\"Ncy\\\":\\\"Н\\\",\\\"ncy\\\":\\\"н\\\",\\\"ndash\\\":\\\"–\\\",\\\"nearhk\\\":\\\"⤤\\\",\\\"nearr\\\":\\\"↗\\\",\\\"neArr\\\":\\\"⇗\\\",\\\"nearrow\\\":\\\"↗\\\",\\\"ne\\\":\\\"≠\\\",\\\"nedot\\\":\\\"≐̸\\\",\\\"NegativeMediumSpace\\\":\\\"​\\\",\\\"NegativeThickSpace\\\":\\\"​\\\",\\\"NegativeThinSpace\\\":\\\"​\\\",\\\"NegativeVeryThinSpace\\\":\\\"​\\\",\\\"nequiv\\\":\\\"≢\\\",\\\"nesear\\\":\\\"⤨\\\",\\\"nesim\\\":\\\"≂̸\\\",\\\"NestedGreaterGreater\\\":\\\"≫\\\",\\\"NestedLessLess\\\":\\\"≪\\\",\\\"NewLine\\\":\\\"\\\\n\\\",\\\"nexist\\\":\\\"∄\\\",\\\"nexists\\\":\\\"∄\\\",\\\"Nfr\\\":\\\"𝔑\\\",\\\"nfr\\\":\\\"𝔫\\\",\\\"ngE\\\":\\\"≧̸\\\",\\\"nge\\\":\\\"≱\\\",\\\"ngeq\\\":\\\"≱\\\",\\\"ngeqq\\\":\\\"≧̸\\\",\\\"ngeqslant\\\":\\\"⩾̸\\\",\\\"nges\\\":\\\"⩾̸\\\",\\\"nGg\\\":\\\"⋙̸\\\",\\\"ngsim\\\":\\\"≵\\\",\\\"nGt\\\":\\\"≫⃒\\\",\\\"ngt\\\":\\\"≯\\\",\\\"ngtr\\\":\\\"≯\\\",\\\"nGtv\\\":\\\"≫̸\\\",\\\"nharr\\\":\\\"↮\\\",\\\"nhArr\\\":\\\"⇎\\\",\\\"nhpar\\\":\\\"⫲\\\",\\\"ni\\\":\\\"∋\\\",\\\"nis\\\":\\\"⋼\\\",\\\"nisd\\\":\\\"⋺\\\",\\\"niv\\\":\\\"∋\\\",\\\"NJcy\\\":\\\"Њ\\\",\\\"njcy\\\":\\\"њ\\\",\\\"nlarr\\\":\\\"↚\\\",\\\"nlArr\\\":\\\"⇍\\\",\\\"nldr\\\":\\\"‥\\\",\\\"nlE\\\":\\\"≦̸\\\",\\\"nle\\\":\\\"≰\\\",\\\"nleftarrow\\\":\\\"↚\\\",\\\"nLeftarrow\\\":\\\"⇍\\\",\\\"nleftrightarrow\\\":\\\"↮\\\",\\\"nLeftrightarrow\\\":\\\"⇎\\\",\\\"nleq\\\":\\\"≰\\\",\\\"nleqq\\\":\\\"≦̸\\\",\\\"nleqslant\\\":\\\"⩽̸\\\",\\\"nles\\\":\\\"⩽̸\\\",\\\"nless\\\":\\\"≮\\\",\\\"nLl\\\":\\\"⋘̸\\\",\\\"nlsim\\\":\\\"≴\\\",\\\"nLt\\\":\\\"≪⃒\\\",\\\"nlt\\\":\\\"≮\\\",\\\"nltri\\\":\\\"⋪\\\",\\\"nltrie\\\":\\\"⋬\\\",\\\"nLtv\\\":\\\"≪̸\\\",\\\"nmid\\\":\\\"∤\\\",\\\"NoBreak\\\":\\\"⁠\\\",\\\"NonBreakingSpace\\\":\\\" \\\",\\\"nopf\\\":\\\"𝕟\\\",\\\"Nopf\\\":\\\"ℕ\\\",\\\"Not\\\":\\\"⫬\\\",\\\"not\\\":\\\"¬\\\",\\\"NotCongruent\\\":\\\"≢\\\",\\\"NotCupCap\\\":\\\"≭\\\",\\\"NotDoubleVerticalBar\\\":\\\"∦\\\",\\\"NotElement\\\":\\\"∉\\\",\\\"NotEqual\\\":\\\"≠\\\",\\\"NotEqualTilde\\\":\\\"≂̸\\\",\\\"NotExists\\\":\\\"∄\\\",\\\"NotGreater\\\":\\\"≯\\\",\\\"NotGreaterEqual\\\":\\\"≱\\\",\\\"NotGreaterFullEqual\\\":\\\"≧̸\\\",\\\"NotGreaterGreater\\\":\\\"≫̸\\\",\\\"NotGreaterLess\\\":\\\"≹\\\",\\\"NotGreaterSlantEqual\\\":\\\"⩾̸\\\",\\\"NotGreaterTilde\\\":\\\"≵\\\",\\\"NotHumpDownHump\\\":\\\"≎̸\\\",\\\"NotHumpEqual\\\":\\\"≏̸\\\",\\\"notin\\\":\\\"∉\\\",\\\"notindot\\\":\\\"⋵̸\\\",\\\"notinE\\\":\\\"⋹̸\\\",\\\"notinva\\\":\\\"∉\\\",\\\"notinvb\\\":\\\"⋷\\\",\\\"notinvc\\\":\\\"⋶\\\",\\\"NotLeftTriangleBar\\\":\\\"⧏̸\\\",\\\"NotLeftTriangle\\\":\\\"⋪\\\",\\\"NotLeftTriangleEqual\\\":\\\"⋬\\\",\\\"NotLess\\\":\\\"≮\\\",\\\"NotLessEqual\\\":\\\"≰\\\",\\\"NotLessGreater\\\":\\\"≸\\\",\\\"NotLessLess\\\":\\\"≪̸\\\",\\\"NotLessSlantEqual\\\":\\\"⩽̸\\\",\\\"NotLessTilde\\\":\\\"≴\\\",\\\"NotNestedGreaterGreater\\\":\\\"⪢̸\\\",\\\"NotNestedLessLess\\\":\\\"⪡̸\\\",\\\"notni\\\":\\\"∌\\\",\\\"notniva\\\":\\\"∌\\\",\\\"notnivb\\\":\\\"⋾\\\",\\\"notnivc\\\":\\\"⋽\\\",\\\"NotPrecedes\\\":\\\"⊀\\\",\\\"NotPrecedesEqual\\\":\\\"⪯̸\\\",\\\"NotPrecedesSlantEqual\\\":\\\"⋠\\\",\\\"NotReverseElement\\\":\\\"∌\\\",\\\"NotRightTriangleBar\\\":\\\"⧐̸\\\",\\\"NotRightTriangle\\\":\\\"⋫\\\",\\\"NotRightTriangleEqual\\\":\\\"⋭\\\",\\\"NotSquareSubset\\\":\\\"⊏̸\\\",\\\"NotSquareSubsetEqual\\\":\\\"⋢\\\",\\\"NotSquareSuperset\\\":\\\"⊐̸\\\",\\\"NotSquareSupersetEqual\\\":\\\"⋣\\\",\\\"NotSubset\\\":\\\"⊂⃒\\\",\\\"NotSubsetEqual\\\":\\\"⊈\\\",\\\"NotSucceeds\\\":\\\"⊁\\\",\\\"NotSucceedsEqual\\\":\\\"⪰̸\\\",\\\"NotSucceedsSlantEqual\\\":\\\"⋡\\\",\\\"NotSucceedsTilde\\\":\\\"≿̸\\\",\\\"NotSuperset\\\":\\\"⊃⃒\\\",\\\"NotSupersetEqual\\\":\\\"⊉\\\",\\\"NotTilde\\\":\\\"≁\\\",\\\"NotTildeEqual\\\":\\\"≄\\\",\\\"NotTildeFullEqual\\\":\\\"≇\\\",\\\"NotTildeTilde\\\":\\\"≉\\\",\\\"NotVerticalBar\\\":\\\"∤\\\",\\\"nparallel\\\":\\\"∦\\\",\\\"npar\\\":\\\"∦\\\",\\\"nparsl\\\":\\\"⫽⃥\\\",\\\"npart\\\":\\\"∂̸\\\",\\\"npolint\\\":\\\"⨔\\\",\\\"npr\\\":\\\"⊀\\\",\\\"nprcue\\\":\\\"⋠\\\",\\\"nprec\\\":\\\"⊀\\\",\\\"npreceq\\\":\\\"⪯̸\\\",\\\"npre\\\":\\\"⪯̸\\\",\\\"nrarrc\\\":\\\"⤳̸\\\",\\\"nrarr\\\":\\\"↛\\\",\\\"nrArr\\\":\\\"⇏\\\",\\\"nrarrw\\\":\\\"↝̸\\\",\\\"nrightarrow\\\":\\\"↛\\\",\\\"nRightarrow\\\":\\\"⇏\\\",\\\"nrtri\\\":\\\"⋫\\\",\\\"nrtrie\\\":\\\"⋭\\\",\\\"nsc\\\":\\\"⊁\\\",\\\"nsccue\\\":\\\"⋡\\\",\\\"nsce\\\":\\\"⪰̸\\\",\\\"Nscr\\\":\\\"𝒩\\\",\\\"nscr\\\":\\\"𝓃\\\",\\\"nshortmid\\\":\\\"∤\\\",\\\"nshortparallel\\\":\\\"∦\\\",\\\"nsim\\\":\\\"≁\\\",\\\"nsime\\\":\\\"≄\\\",\\\"nsimeq\\\":\\\"≄\\\",\\\"nsmid\\\":\\\"∤\\\",\\\"nspar\\\":\\\"∦\\\",\\\"nsqsube\\\":\\\"⋢\\\",\\\"nsqsupe\\\":\\\"⋣\\\",\\\"nsub\\\":\\\"⊄\\\",\\\"nsubE\\\":\\\"⫅̸\\\",\\\"nsube\\\":\\\"⊈\\\",\\\"nsubset\\\":\\\"⊂⃒\\\",\\\"nsubseteq\\\":\\\"⊈\\\",\\\"nsubseteqq\\\":\\\"⫅̸\\\",\\\"nsucc\\\":\\\"⊁\\\",\\\"nsucceq\\\":\\\"⪰̸\\\",\\\"nsup\\\":\\\"⊅\\\",\\\"nsupE\\\":\\\"⫆̸\\\",\\\"nsupe\\\":\\\"⊉\\\",\\\"nsupset\\\":\\\"⊃⃒\\\",\\\"nsupseteq\\\":\\\"⊉\\\",\\\"nsupseteqq\\\":\\\"⫆̸\\\",\\\"ntgl\\\":\\\"≹\\\",\\\"Ntilde\\\":\\\"Ñ\\\",\\\"ntilde\\\":\\\"ñ\\\",\\\"ntlg\\\":\\\"≸\\\",\\\"ntriangleleft\\\":\\\"⋪\\\",\\\"ntrianglelefteq\\\":\\\"⋬\\\",\\\"ntriangleright\\\":\\\"⋫\\\",\\\"ntrianglerighteq\\\":\\\"⋭\\\",\\\"Nu\\\":\\\"Ν\\\",\\\"nu\\\":\\\"ν\\\",\\\"num\\\":\\\"#\\\",\\\"numero\\\":\\\"№\\\",\\\"numsp\\\":\\\" \\\",\\\"nvap\\\":\\\"≍⃒\\\",\\\"nvdash\\\":\\\"⊬\\\",\\\"nvDash\\\":\\\"⊭\\\",\\\"nVdash\\\":\\\"⊮\\\",\\\"nVDash\\\":\\\"⊯\\\",\\\"nvge\\\":\\\"≥⃒\\\",\\\"nvgt\\\":\\\">⃒\\\",\\\"nvHarr\\\":\\\"⤄\\\",\\\"nvinfin\\\":\\\"⧞\\\",\\\"nvlArr\\\":\\\"⤂\\\",\\\"nvle\\\":\\\"≤⃒\\\",\\\"nvlt\\\":\\\"<⃒\\\",\\\"nvltrie\\\":\\\"⊴⃒\\\",\\\"nvrArr\\\":\\\"⤃\\\",\\\"nvrtrie\\\":\\\"⊵⃒\\\",\\\"nvsim\\\":\\\"∼⃒\\\",\\\"nwarhk\\\":\\\"⤣\\\",\\\"nwarr\\\":\\\"↖\\\",\\\"nwArr\\\":\\\"⇖\\\",\\\"nwarrow\\\":\\\"↖\\\",\\\"nwnear\\\":\\\"⤧\\\",\\\"Oacute\\\":\\\"Ó\\\",\\\"oacute\\\":\\\"ó\\\",\\\"oast\\\":\\\"⊛\\\",\\\"Ocirc\\\":\\\"Ô\\\",\\\"ocirc\\\":\\\"ô\\\",\\\"ocir\\\":\\\"⊚\\\",\\\"Ocy\\\":\\\"О\\\",\\\"ocy\\\":\\\"о\\\",\\\"odash\\\":\\\"⊝\\\",\\\"Odblac\\\":\\\"Ő\\\",\\\"odblac\\\":\\\"ő\\\",\\\"odiv\\\":\\\"⨸\\\",\\\"odot\\\":\\\"⊙\\\",\\\"odsold\\\":\\\"⦼\\\",\\\"OElig\\\":\\\"Œ\\\",\\\"oelig\\\":\\\"œ\\\",\\\"ofcir\\\":\\\"⦿\\\",\\\"Ofr\\\":\\\"𝔒\\\",\\\"ofr\\\":\\\"𝔬\\\",\\\"ogon\\\":\\\"˛\\\",\\\"Ograve\\\":\\\"Ò\\\",\\\"ograve\\\":\\\"ò\\\",\\\"ogt\\\":\\\"⧁\\\",\\\"ohbar\\\":\\\"⦵\\\",\\\"ohm\\\":\\\"Ω\\\",\\\"oint\\\":\\\"∮\\\",\\\"olarr\\\":\\\"↺\\\",\\\"olcir\\\":\\\"⦾\\\",\\\"olcross\\\":\\\"⦻\\\",\\\"oline\\\":\\\"‾\\\",\\\"olt\\\":\\\"⧀\\\",\\\"Omacr\\\":\\\"Ō\\\",\\\"omacr\\\":\\\"ō\\\",\\\"Omega\\\":\\\"Ω\\\",\\\"omega\\\":\\\"ω\\\",\\\"Omicron\\\":\\\"Ο\\\",\\\"omicron\\\":\\\"ο\\\",\\\"omid\\\":\\\"⦶\\\",\\\"ominus\\\":\\\"⊖\\\",\\\"Oopf\\\":\\\"𝕆\\\",\\\"oopf\\\":\\\"𝕠\\\",\\\"opar\\\":\\\"⦷\\\",\\\"OpenCurlyDoubleQuote\\\":\\\"“\\\",\\\"OpenCurlyQuote\\\":\\\"‘\\\",\\\"operp\\\":\\\"⦹\\\",\\\"oplus\\\":\\\"⊕\\\",\\\"orarr\\\":\\\"↻\\\",\\\"Or\\\":\\\"⩔\\\",\\\"or\\\":\\\"∨\\\",\\\"ord\\\":\\\"⩝\\\",\\\"order\\\":\\\"ℴ\\\",\\\"orderof\\\":\\\"ℴ\\\",\\\"ordf\\\":\\\"ª\\\",\\\"ordm\\\":\\\"º\\\",\\\"origof\\\":\\\"⊶\\\",\\\"oror\\\":\\\"⩖\\\",\\\"orslope\\\":\\\"⩗\\\",\\\"orv\\\":\\\"⩛\\\",\\\"oS\\\":\\\"Ⓢ\\\",\\\"Oscr\\\":\\\"𝒪\\\",\\\"oscr\\\":\\\"ℴ\\\",\\\"Oslash\\\":\\\"Ø\\\",\\\"oslash\\\":\\\"ø\\\",\\\"osol\\\":\\\"⊘\\\",\\\"Otilde\\\":\\\"Õ\\\",\\\"otilde\\\":\\\"õ\\\",\\\"otimesas\\\":\\\"⨶\\\",\\\"Otimes\\\":\\\"⨷\\\",\\\"otimes\\\":\\\"⊗\\\",\\\"Ouml\\\":\\\"Ö\\\",\\\"ouml\\\":\\\"ö\\\",\\\"ovbar\\\":\\\"⌽\\\",\\\"OverBar\\\":\\\"‾\\\",\\\"OverBrace\\\":\\\"⏞\\\",\\\"OverBracket\\\":\\\"⎴\\\",\\\"OverParenthesis\\\":\\\"⏜\\\",\\\"para\\\":\\\"¶\\\",\\\"parallel\\\":\\\"∥\\\",\\\"par\\\":\\\"∥\\\",\\\"parsim\\\":\\\"⫳\\\",\\\"parsl\\\":\\\"⫽\\\",\\\"part\\\":\\\"∂\\\",\\\"PartialD\\\":\\\"∂\\\",\\\"Pcy\\\":\\\"П\\\",\\\"pcy\\\":\\\"п\\\",\\\"percnt\\\":\\\"%\\\",\\\"period\\\":\\\".\\\",\\\"permil\\\":\\\"‰\\\",\\\"perp\\\":\\\"⊥\\\",\\\"pertenk\\\":\\\"‱\\\",\\\"Pfr\\\":\\\"𝔓\\\",\\\"pfr\\\":\\\"𝔭\\\",\\\"Phi\\\":\\\"Φ\\\",\\\"phi\\\":\\\"φ\\\",\\\"phiv\\\":\\\"ϕ\\\",\\\"phmmat\\\":\\\"ℳ\\\",\\\"phone\\\":\\\"☎\\\",\\\"Pi\\\":\\\"Π\\\",\\\"pi\\\":\\\"π\\\",\\\"pitchfork\\\":\\\"⋔\\\",\\\"piv\\\":\\\"ϖ\\\",\\\"planck\\\":\\\"ℏ\\\",\\\"planckh\\\":\\\"ℎ\\\",\\\"plankv\\\":\\\"ℏ\\\",\\\"plusacir\\\":\\\"⨣\\\",\\\"plusb\\\":\\\"⊞\\\",\\\"pluscir\\\":\\\"⨢\\\",\\\"plus\\\":\\\"+\\\",\\\"plusdo\\\":\\\"∔\\\",\\\"plusdu\\\":\\\"⨥\\\",\\\"pluse\\\":\\\"⩲\\\",\\\"PlusMinus\\\":\\\"±\\\",\\\"plusmn\\\":\\\"±\\\",\\\"plussim\\\":\\\"⨦\\\",\\\"plustwo\\\":\\\"⨧\\\",\\\"pm\\\":\\\"±\\\",\\\"Poincareplane\\\":\\\"ℌ\\\",\\\"pointint\\\":\\\"⨕\\\",\\\"popf\\\":\\\"𝕡\\\",\\\"Popf\\\":\\\"ℙ\\\",\\\"pound\\\":\\\"£\\\",\\\"prap\\\":\\\"⪷\\\",\\\"Pr\\\":\\\"⪻\\\",\\\"pr\\\":\\\"≺\\\",\\\"prcue\\\":\\\"≼\\\",\\\"precapprox\\\":\\\"⪷\\\",\\\"prec\\\":\\\"≺\\\",\\\"preccurlyeq\\\":\\\"≼\\\",\\\"Precedes\\\":\\\"≺\\\",\\\"PrecedesEqual\\\":\\\"⪯\\\",\\\"PrecedesSlantEqual\\\":\\\"≼\\\",\\\"PrecedesTilde\\\":\\\"≾\\\",\\\"preceq\\\":\\\"⪯\\\",\\\"precnapprox\\\":\\\"⪹\\\",\\\"precneqq\\\":\\\"⪵\\\",\\\"precnsim\\\":\\\"⋨\\\",\\\"pre\\\":\\\"⪯\\\",\\\"prE\\\":\\\"⪳\\\",\\\"precsim\\\":\\\"≾\\\",\\\"prime\\\":\\\"′\\\",\\\"Prime\\\":\\\"″\\\",\\\"primes\\\":\\\"ℙ\\\",\\\"prnap\\\":\\\"⪹\\\",\\\"prnE\\\":\\\"⪵\\\",\\\"prnsim\\\":\\\"⋨\\\",\\\"prod\\\":\\\"∏\\\",\\\"Product\\\":\\\"∏\\\",\\\"profalar\\\":\\\"⌮\\\",\\\"profline\\\":\\\"⌒\\\",\\\"profsurf\\\":\\\"⌓\\\",\\\"prop\\\":\\\"∝\\\",\\\"Proportional\\\":\\\"∝\\\",\\\"Proportion\\\":\\\"∷\\\",\\\"propto\\\":\\\"∝\\\",\\\"prsim\\\":\\\"≾\\\",\\\"prurel\\\":\\\"⊰\\\",\\\"Pscr\\\":\\\"𝒫\\\",\\\"pscr\\\":\\\"𝓅\\\",\\\"Psi\\\":\\\"Ψ\\\",\\\"psi\\\":\\\"ψ\\\",\\\"puncsp\\\":\\\" \\\",\\\"Qfr\\\":\\\"𝔔\\\",\\\"qfr\\\":\\\"𝔮\\\",\\\"qint\\\":\\\"⨌\\\",\\\"qopf\\\":\\\"𝕢\\\",\\\"Qopf\\\":\\\"ℚ\\\",\\\"qprime\\\":\\\"⁗\\\",\\\"Qscr\\\":\\\"𝒬\\\",\\\"qscr\\\":\\\"𝓆\\\",\\\"quaternions\\\":\\\"ℍ\\\",\\\"quatint\\\":\\\"⨖\\\",\\\"quest\\\":\\\"?\\\",\\\"questeq\\\":\\\"≟\\\",\\\"quot\\\":\\\"\\\\\\\"\\\",\\\"QUOT\\\":\\\"\\\\\\\"\\\",\\\"rAarr\\\":\\\"⇛\\\",\\\"race\\\":\\\"∽̱\\\",\\\"Racute\\\":\\\"Ŕ\\\",\\\"racute\\\":\\\"ŕ\\\",\\\"radic\\\":\\\"√\\\",\\\"raemptyv\\\":\\\"⦳\\\",\\\"rang\\\":\\\"⟩\\\",\\\"Rang\\\":\\\"⟫\\\",\\\"rangd\\\":\\\"⦒\\\",\\\"range\\\":\\\"⦥\\\",\\\"rangle\\\":\\\"⟩\\\",\\\"raquo\\\":\\\"»\\\",\\\"rarrap\\\":\\\"⥵\\\",\\\"rarrb\\\":\\\"⇥\\\",\\\"rarrbfs\\\":\\\"⤠\\\",\\\"rarrc\\\":\\\"⤳\\\",\\\"rarr\\\":\\\"→\\\",\\\"Rarr\\\":\\\"↠\\\",\\\"rArr\\\":\\\"⇒\\\",\\\"rarrfs\\\":\\\"⤞\\\",\\\"rarrhk\\\":\\\"↪\\\",\\\"rarrlp\\\":\\\"↬\\\",\\\"rarrpl\\\":\\\"⥅\\\",\\\"rarrsim\\\":\\\"⥴\\\",\\\"Rarrtl\\\":\\\"⤖\\\",\\\"rarrtl\\\":\\\"↣\\\",\\\"rarrw\\\":\\\"↝\\\",\\\"ratail\\\":\\\"⤚\\\",\\\"rAtail\\\":\\\"⤜\\\",\\\"ratio\\\":\\\"∶\\\",\\\"rationals\\\":\\\"ℚ\\\",\\\"rbarr\\\":\\\"⤍\\\",\\\"rBarr\\\":\\\"⤏\\\",\\\"RBarr\\\":\\\"⤐\\\",\\\"rbbrk\\\":\\\"❳\\\",\\\"rbrace\\\":\\\"}\\\",\\\"rbrack\\\":\\\"]\\\",\\\"rbrke\\\":\\\"⦌\\\",\\\"rbrksld\\\":\\\"⦎\\\",\\\"rbrkslu\\\":\\\"⦐\\\",\\\"Rcaron\\\":\\\"Ř\\\",\\\"rcaron\\\":\\\"ř\\\",\\\"Rcedil\\\":\\\"Ŗ\\\",\\\"rcedil\\\":\\\"ŗ\\\",\\\"rceil\\\":\\\"⌉\\\",\\\"rcub\\\":\\\"}\\\",\\\"Rcy\\\":\\\"Р\\\",\\\"rcy\\\":\\\"р\\\",\\\"rdca\\\":\\\"⤷\\\",\\\"rdldhar\\\":\\\"⥩\\\",\\\"rdquo\\\":\\\"”\\\",\\\"rdquor\\\":\\\"”\\\",\\\"rdsh\\\":\\\"↳\\\",\\\"real\\\":\\\"ℜ\\\",\\\"realine\\\":\\\"ℛ\\\",\\\"realpart\\\":\\\"ℜ\\\",\\\"reals\\\":\\\"ℝ\\\",\\\"Re\\\":\\\"ℜ\\\",\\\"rect\\\":\\\"▭\\\",\\\"reg\\\":\\\"®\\\",\\\"REG\\\":\\\"®\\\",\\\"ReverseElement\\\":\\\"∋\\\",\\\"ReverseEquilibrium\\\":\\\"⇋\\\",\\\"ReverseUpEquilibrium\\\":\\\"⥯\\\",\\\"rfisht\\\":\\\"⥽\\\",\\\"rfloor\\\":\\\"⌋\\\",\\\"rfr\\\":\\\"𝔯\\\",\\\"Rfr\\\":\\\"ℜ\\\",\\\"rHar\\\":\\\"⥤\\\",\\\"rhard\\\":\\\"⇁\\\",\\\"rharu\\\":\\\"⇀\\\",\\\"rharul\\\":\\\"⥬\\\",\\\"Rho\\\":\\\"Ρ\\\",\\\"rho\\\":\\\"ρ\\\",\\\"rhov\\\":\\\"ϱ\\\",\\\"RightAngleBracket\\\":\\\"⟩\\\",\\\"RightArrowBar\\\":\\\"⇥\\\",\\\"rightarrow\\\":\\\"→\\\",\\\"RightArrow\\\":\\\"→\\\",\\\"Rightarrow\\\":\\\"⇒\\\",\\\"RightArrowLeftArrow\\\":\\\"⇄\\\",\\\"rightarrowtail\\\":\\\"↣\\\",\\\"RightCeiling\\\":\\\"⌉\\\",\\\"RightDoubleBracket\\\":\\\"⟧\\\",\\\"RightDownTeeVector\\\":\\\"⥝\\\",\\\"RightDownVectorBar\\\":\\\"⥕\\\",\\\"RightDownVector\\\":\\\"⇂\\\",\\\"RightFloor\\\":\\\"⌋\\\",\\\"rightharpoondown\\\":\\\"⇁\\\",\\\"rightharpoonup\\\":\\\"⇀\\\",\\\"rightleftarrows\\\":\\\"⇄\\\",\\\"rightleftharpoons\\\":\\\"⇌\\\",\\\"rightrightarrows\\\":\\\"⇉\\\",\\\"rightsquigarrow\\\":\\\"↝\\\",\\\"RightTeeArrow\\\":\\\"↦\\\",\\\"RightTee\\\":\\\"⊢\\\",\\\"RightTeeVector\\\":\\\"⥛\\\",\\\"rightthreetimes\\\":\\\"⋌\\\",\\\"RightTriangleBar\\\":\\\"⧐\\\",\\\"RightTriangle\\\":\\\"⊳\\\",\\\"RightTriangleEqual\\\":\\\"⊵\\\",\\\"RightUpDownVector\\\":\\\"⥏\\\",\\\"RightUpTeeVector\\\":\\\"⥜\\\",\\\"RightUpVectorBar\\\":\\\"⥔\\\",\\\"RightUpVector\\\":\\\"↾\\\",\\\"RightVectorBar\\\":\\\"⥓\\\",\\\"RightVector\\\":\\\"⇀\\\",\\\"ring\\\":\\\"˚\\\",\\\"risingdotseq\\\":\\\"≓\\\",\\\"rlarr\\\":\\\"⇄\\\",\\\"rlhar\\\":\\\"⇌\\\",\\\"rlm\\\":\\\"‏\\\",\\\"rmoustache\\\":\\\"⎱\\\",\\\"rmoust\\\":\\\"⎱\\\",\\\"rnmid\\\":\\\"⫮\\\",\\\"roang\\\":\\\"⟭\\\",\\\"roarr\\\":\\\"⇾\\\",\\\"robrk\\\":\\\"⟧\\\",\\\"ropar\\\":\\\"⦆\\\",\\\"ropf\\\":\\\"𝕣\\\",\\\"Ropf\\\":\\\"ℝ\\\",\\\"roplus\\\":\\\"⨮\\\",\\\"rotimes\\\":\\\"⨵\\\",\\\"RoundImplies\\\":\\\"⥰\\\",\\\"rpar\\\":\\\")\\\",\\\"rpargt\\\":\\\"⦔\\\",\\\"rppolint\\\":\\\"⨒\\\",\\\"rrarr\\\":\\\"⇉\\\",\\\"Rrightarrow\\\":\\\"⇛\\\",\\\"rsaquo\\\":\\\"›\\\",\\\"rscr\\\":\\\"𝓇\\\",\\\"Rscr\\\":\\\"ℛ\\\",\\\"rsh\\\":\\\"↱\\\",\\\"Rsh\\\":\\\"↱\\\",\\\"rsqb\\\":\\\"]\\\",\\\"rsquo\\\":\\\"’\\\",\\\"rsquor\\\":\\\"’\\\",\\\"rthree\\\":\\\"⋌\\\",\\\"rtimes\\\":\\\"⋊\\\",\\\"rtri\\\":\\\"▹\\\",\\\"rtrie\\\":\\\"⊵\\\",\\\"rtrif\\\":\\\"▸\\\",\\\"rtriltri\\\":\\\"⧎\\\",\\\"RuleDelayed\\\":\\\"⧴\\\",\\\"ruluhar\\\":\\\"⥨\\\",\\\"rx\\\":\\\"℞\\\",\\\"Sacute\\\":\\\"Ś\\\",\\\"sacute\\\":\\\"ś\\\",\\\"sbquo\\\":\\\"‚\\\",\\\"scap\\\":\\\"⪸\\\",\\\"Scaron\\\":\\\"Š\\\",\\\"scaron\\\":\\\"š\\\",\\\"Sc\\\":\\\"⪼\\\",\\\"sc\\\":\\\"≻\\\",\\\"sccue\\\":\\\"≽\\\",\\\"sce\\\":\\\"⪰\\\",\\\"scE\\\":\\\"⪴\\\",\\\"Scedil\\\":\\\"Ş\\\",\\\"scedil\\\":\\\"ş\\\",\\\"Scirc\\\":\\\"Ŝ\\\",\\\"scirc\\\":\\\"ŝ\\\",\\\"scnap\\\":\\\"⪺\\\",\\\"scnE\\\":\\\"⪶\\\",\\\"scnsim\\\":\\\"⋩\\\",\\\"scpolint\\\":\\\"⨓\\\",\\\"scsim\\\":\\\"≿\\\",\\\"Scy\\\":\\\"С\\\",\\\"scy\\\":\\\"с\\\",\\\"sdotb\\\":\\\"⊡\\\",\\\"sdot\\\":\\\"⋅\\\",\\\"sdote\\\":\\\"⩦\\\",\\\"searhk\\\":\\\"⤥\\\",\\\"searr\\\":\\\"↘\\\",\\\"seArr\\\":\\\"⇘\\\",\\\"searrow\\\":\\\"↘\\\",\\\"sect\\\":\\\"§\\\",\\\"semi\\\":\\\";\\\",\\\"seswar\\\":\\\"⤩\\\",\\\"setminus\\\":\\\"∖\\\",\\\"setmn\\\":\\\"∖\\\",\\\"sext\\\":\\\"✶\\\",\\\"Sfr\\\":\\\"𝔖\\\",\\\"sfr\\\":\\\"𝔰\\\",\\\"sfrown\\\":\\\"⌢\\\",\\\"sharp\\\":\\\"♯\\\",\\\"SHCHcy\\\":\\\"Щ\\\",\\\"shchcy\\\":\\\"щ\\\",\\\"SHcy\\\":\\\"Ш\\\",\\\"shcy\\\":\\\"ш\\\",\\\"ShortDownArrow\\\":\\\"↓\\\",\\\"ShortLeftArrow\\\":\\\"←\\\",\\\"shortmid\\\":\\\"∣\\\",\\\"shortparallel\\\":\\\"∥\\\",\\\"ShortRightArrow\\\":\\\"→\\\",\\\"ShortUpArrow\\\":\\\"↑\\\",\\\"shy\\\":\\\"­\\\",\\\"Sigma\\\":\\\"Σ\\\",\\\"sigma\\\":\\\"σ\\\",\\\"sigmaf\\\":\\\"ς\\\",\\\"sigmav\\\":\\\"ς\\\",\\\"sim\\\":\\\"∼\\\",\\\"simdot\\\":\\\"⩪\\\",\\\"sime\\\":\\\"≃\\\",\\\"simeq\\\":\\\"≃\\\",\\\"simg\\\":\\\"⪞\\\",\\\"simgE\\\":\\\"⪠\\\",\\\"siml\\\":\\\"⪝\\\",\\\"simlE\\\":\\\"⪟\\\",\\\"simne\\\":\\\"≆\\\",\\\"simplus\\\":\\\"⨤\\\",\\\"simrarr\\\":\\\"⥲\\\",\\\"slarr\\\":\\\"←\\\",\\\"SmallCircle\\\":\\\"∘\\\",\\\"smallsetminus\\\":\\\"∖\\\",\\\"smashp\\\":\\\"⨳\\\",\\\"smeparsl\\\":\\\"⧤\\\",\\\"smid\\\":\\\"∣\\\",\\\"smile\\\":\\\"⌣\\\",\\\"smt\\\":\\\"⪪\\\",\\\"smte\\\":\\\"⪬\\\",\\\"smtes\\\":\\\"⪬︀\\\",\\\"SOFTcy\\\":\\\"Ь\\\",\\\"softcy\\\":\\\"ь\\\",\\\"solbar\\\":\\\"⌿\\\",\\\"solb\\\":\\\"⧄\\\",\\\"sol\\\":\\\"/\\\",\\\"Sopf\\\":\\\"𝕊\\\",\\\"sopf\\\":\\\"𝕤\\\",\\\"spades\\\":\\\"♠\\\",\\\"spadesuit\\\":\\\"♠\\\",\\\"spar\\\":\\\"∥\\\",\\\"sqcap\\\":\\\"⊓\\\",\\\"sqcaps\\\":\\\"⊓︀\\\",\\\"sqcup\\\":\\\"⊔\\\",\\\"sqcups\\\":\\\"⊔︀\\\",\\\"Sqrt\\\":\\\"√\\\",\\\"sqsub\\\":\\\"⊏\\\",\\\"sqsube\\\":\\\"⊑\\\",\\\"sqsubset\\\":\\\"⊏\\\",\\\"sqsubseteq\\\":\\\"⊑\\\",\\\"sqsup\\\":\\\"⊐\\\",\\\"sqsupe\\\":\\\"⊒\\\",\\\"sqsupset\\\":\\\"⊐\\\",\\\"sqsupseteq\\\":\\\"⊒\\\",\\\"square\\\":\\\"□\\\",\\\"Square\\\":\\\"□\\\",\\\"SquareIntersection\\\":\\\"⊓\\\",\\\"SquareSubset\\\":\\\"⊏\\\",\\\"SquareSubsetEqual\\\":\\\"⊑\\\",\\\"SquareSuperset\\\":\\\"⊐\\\",\\\"SquareSupersetEqual\\\":\\\"⊒\\\",\\\"SquareUnion\\\":\\\"⊔\\\",\\\"squarf\\\":\\\"▪\\\",\\\"squ\\\":\\\"□\\\",\\\"squf\\\":\\\"▪\\\",\\\"srarr\\\":\\\"→\\\",\\\"Sscr\\\":\\\"𝒮\\\",\\\"sscr\\\":\\\"𝓈\\\",\\\"ssetmn\\\":\\\"∖\\\",\\\"ssmile\\\":\\\"⌣\\\",\\\"sstarf\\\":\\\"⋆\\\",\\\"Star\\\":\\\"⋆\\\",\\\"star\\\":\\\"☆\\\",\\\"starf\\\":\\\"★\\\",\\\"straightepsilon\\\":\\\"ϵ\\\",\\\"straightphi\\\":\\\"ϕ\\\",\\\"strns\\\":\\\"¯\\\",\\\"sub\\\":\\\"⊂\\\",\\\"Sub\\\":\\\"⋐\\\",\\\"subdot\\\":\\\"⪽\\\",\\\"subE\\\":\\\"⫅\\\",\\\"sube\\\":\\\"⊆\\\",\\\"subedot\\\":\\\"⫃\\\",\\\"submult\\\":\\\"⫁\\\",\\\"subnE\\\":\\\"⫋\\\",\\\"subne\\\":\\\"⊊\\\",\\\"subplus\\\":\\\"⪿\\\",\\\"subrarr\\\":\\\"⥹\\\",\\\"subset\\\":\\\"⊂\\\",\\\"Subset\\\":\\\"⋐\\\",\\\"subseteq\\\":\\\"⊆\\\",\\\"subseteqq\\\":\\\"⫅\\\",\\\"SubsetEqual\\\":\\\"⊆\\\",\\\"subsetneq\\\":\\\"⊊\\\",\\\"subsetneqq\\\":\\\"⫋\\\",\\\"subsim\\\":\\\"⫇\\\",\\\"subsub\\\":\\\"⫕\\\",\\\"subsup\\\":\\\"⫓\\\",\\\"succapprox\\\":\\\"⪸\\\",\\\"succ\\\":\\\"≻\\\",\\\"succcurlyeq\\\":\\\"≽\\\",\\\"Succeeds\\\":\\\"≻\\\",\\\"SucceedsEqual\\\":\\\"⪰\\\",\\\"SucceedsSlantEqual\\\":\\\"≽\\\",\\\"SucceedsTilde\\\":\\\"≿\\\",\\\"succeq\\\":\\\"⪰\\\",\\\"succnapprox\\\":\\\"⪺\\\",\\\"succneqq\\\":\\\"⪶\\\",\\\"succnsim\\\":\\\"⋩\\\",\\\"succsim\\\":\\\"≿\\\",\\\"SuchThat\\\":\\\"∋\\\",\\\"sum\\\":\\\"∑\\\",\\\"Sum\\\":\\\"∑\\\",\\\"sung\\\":\\\"♪\\\",\\\"sup1\\\":\\\"¹\\\",\\\"sup2\\\":\\\"²\\\",\\\"sup3\\\":\\\"³\\\",\\\"sup\\\":\\\"⊃\\\",\\\"Sup\\\":\\\"⋑\\\",\\\"supdot\\\":\\\"⪾\\\",\\\"supdsub\\\":\\\"⫘\\\",\\\"supE\\\":\\\"⫆\\\",\\\"supe\\\":\\\"⊇\\\",\\\"supedot\\\":\\\"⫄\\\",\\\"Superset\\\":\\\"⊃\\\",\\\"SupersetEqual\\\":\\\"⊇\\\",\\\"suphsol\\\":\\\"⟉\\\",\\\"suphsub\\\":\\\"⫗\\\",\\\"suplarr\\\":\\\"⥻\\\",\\\"supmult\\\":\\\"⫂\\\",\\\"supnE\\\":\\\"⫌\\\",\\\"supne\\\":\\\"⊋\\\",\\\"supplus\\\":\\\"⫀\\\",\\\"supset\\\":\\\"⊃\\\",\\\"Supset\\\":\\\"⋑\\\",\\\"supseteq\\\":\\\"⊇\\\",\\\"supseteqq\\\":\\\"⫆\\\",\\\"supsetneq\\\":\\\"⊋\\\",\\\"supsetneqq\\\":\\\"⫌\\\",\\\"supsim\\\":\\\"⫈\\\",\\\"supsub\\\":\\\"⫔\\\",\\\"supsup\\\":\\\"⫖\\\",\\\"swarhk\\\":\\\"⤦\\\",\\\"swarr\\\":\\\"↙\\\",\\\"swArr\\\":\\\"⇙\\\",\\\"swarrow\\\":\\\"↙\\\",\\\"swnwar\\\":\\\"⤪\\\",\\\"szlig\\\":\\\"ß\\\",\\\"Tab\\\":\\\"\\\\t\\\",\\\"target\\\":\\\"⌖\\\",\\\"Tau\\\":\\\"Τ\\\",\\\"tau\\\":\\\"τ\\\",\\\"tbrk\\\":\\\"⎴\\\",\\\"Tcaron\\\":\\\"Ť\\\",\\\"tcaron\\\":\\\"ť\\\",\\\"Tcedil\\\":\\\"Ţ\\\",\\\"tcedil\\\":\\\"ţ\\\",\\\"Tcy\\\":\\\"Т\\\",\\\"tcy\\\":\\\"т\\\",\\\"tdot\\\":\\\"⃛\\\",\\\"telrec\\\":\\\"⌕\\\",\\\"Tfr\\\":\\\"𝔗\\\",\\\"tfr\\\":\\\"𝔱\\\",\\\"there4\\\":\\\"∴\\\",\\\"therefore\\\":\\\"∴\\\",\\\"Therefore\\\":\\\"∴\\\",\\\"Theta\\\":\\\"Θ\\\",\\\"theta\\\":\\\"θ\\\",\\\"thetasym\\\":\\\"ϑ\\\",\\\"thetav\\\":\\\"ϑ\\\",\\\"thickapprox\\\":\\\"≈\\\",\\\"thicksim\\\":\\\"∼\\\",\\\"ThickSpace\\\":\\\"  \\\",\\\"ThinSpace\\\":\\\" \\\",\\\"thinsp\\\":\\\" \\\",\\\"thkap\\\":\\\"≈\\\",\\\"thksim\\\":\\\"∼\\\",\\\"THORN\\\":\\\"Þ\\\",\\\"thorn\\\":\\\"þ\\\",\\\"tilde\\\":\\\"˜\\\",\\\"Tilde\\\":\\\"∼\\\",\\\"TildeEqual\\\":\\\"≃\\\",\\\"TildeFullEqual\\\":\\\"≅\\\",\\\"TildeTilde\\\":\\\"≈\\\",\\\"timesbar\\\":\\\"⨱\\\",\\\"timesb\\\":\\\"⊠\\\",\\\"times\\\":\\\"×\\\",\\\"timesd\\\":\\\"⨰\\\",\\\"tint\\\":\\\"∭\\\",\\\"toea\\\":\\\"⤨\\\",\\\"topbot\\\":\\\"⌶\\\",\\\"topcir\\\":\\\"⫱\\\",\\\"top\\\":\\\"⊤\\\",\\\"Topf\\\":\\\"𝕋\\\",\\\"topf\\\":\\\"𝕥\\\",\\\"topfork\\\":\\\"⫚\\\",\\\"tosa\\\":\\\"⤩\\\",\\\"tprime\\\":\\\"‴\\\",\\\"trade\\\":\\\"™\\\",\\\"TRADE\\\":\\\"™\\\",\\\"triangle\\\":\\\"▵\\\",\\\"triangledown\\\":\\\"▿\\\",\\\"triangleleft\\\":\\\"◃\\\",\\\"trianglelefteq\\\":\\\"⊴\\\",\\\"triangleq\\\":\\\"≜\\\",\\\"triangleright\\\":\\\"▹\\\",\\\"trianglerighteq\\\":\\\"⊵\\\",\\\"tridot\\\":\\\"◬\\\",\\\"trie\\\":\\\"≜\\\",\\\"triminus\\\":\\\"⨺\\\",\\\"TripleDot\\\":\\\"⃛\\\",\\\"triplus\\\":\\\"⨹\\\",\\\"trisb\\\":\\\"⧍\\\",\\\"tritime\\\":\\\"⨻\\\",\\\"trpezium\\\":\\\"⏢\\\",\\\"Tscr\\\":\\\"𝒯\\\",\\\"tscr\\\":\\\"𝓉\\\",\\\"TScy\\\":\\\"Ц\\\",\\\"tscy\\\":\\\"ц\\\",\\\"TSHcy\\\":\\\"Ћ\\\",\\\"tshcy\\\":\\\"ћ\\\",\\\"Tstrok\\\":\\\"Ŧ\\\",\\\"tstrok\\\":\\\"ŧ\\\",\\\"twixt\\\":\\\"≬\\\",\\\"twoheadleftarrow\\\":\\\"↞\\\",\\\"twoheadrightarrow\\\":\\\"↠\\\",\\\"Uacute\\\":\\\"Ú\\\",\\\"uacute\\\":\\\"ú\\\",\\\"uarr\\\":\\\"↑\\\",\\\"Uarr\\\":\\\"↟\\\",\\\"uArr\\\":\\\"⇑\\\",\\\"Uarrocir\\\":\\\"⥉\\\",\\\"Ubrcy\\\":\\\"Ў\\\",\\\"ubrcy\\\":\\\"ў\\\",\\\"Ubreve\\\":\\\"Ŭ\\\",\\\"ubreve\\\":\\\"ŭ\\\",\\\"Ucirc\\\":\\\"Û\\\",\\\"ucirc\\\":\\\"û\\\",\\\"Ucy\\\":\\\"У\\\",\\\"ucy\\\":\\\"у\\\",\\\"udarr\\\":\\\"⇅\\\",\\\"Udblac\\\":\\\"Ű\\\",\\\"udblac\\\":\\\"ű\\\",\\\"udhar\\\":\\\"⥮\\\",\\\"ufisht\\\":\\\"⥾\\\",\\\"Ufr\\\":\\\"𝔘\\\",\\\"ufr\\\":\\\"𝔲\\\",\\\"Ugrave\\\":\\\"Ù\\\",\\\"ugrave\\\":\\\"ù\\\",\\\"uHar\\\":\\\"⥣\\\",\\\"uharl\\\":\\\"↿\\\",\\\"uharr\\\":\\\"↾\\\",\\\"uhblk\\\":\\\"▀\\\",\\\"ulcorn\\\":\\\"⌜\\\",\\\"ulcorner\\\":\\\"⌜\\\",\\\"ulcrop\\\":\\\"⌏\\\",\\\"ultri\\\":\\\"◸\\\",\\\"Umacr\\\":\\\"Ū\\\",\\\"umacr\\\":\\\"ū\\\",\\\"uml\\\":\\\"¨\\\",\\\"UnderBar\\\":\\\"_\\\",\\\"UnderBrace\\\":\\\"⏟\\\",\\\"UnderBracket\\\":\\\"⎵\\\",\\\"UnderParenthesis\\\":\\\"⏝\\\",\\\"Union\\\":\\\"⋃\\\",\\\"UnionPlus\\\":\\\"⊎\\\",\\\"Uogon\\\":\\\"Ų\\\",\\\"uogon\\\":\\\"ų\\\",\\\"Uopf\\\":\\\"𝕌\\\",\\\"uopf\\\":\\\"𝕦\\\",\\\"UpArrowBar\\\":\\\"⤒\\\",\\\"uparrow\\\":\\\"↑\\\",\\\"UpArrow\\\":\\\"↑\\\",\\\"Uparrow\\\":\\\"⇑\\\",\\\"UpArrowDownArrow\\\":\\\"⇅\\\",\\\"updownarrow\\\":\\\"↕\\\",\\\"UpDownArrow\\\":\\\"↕\\\",\\\"Updownarrow\\\":\\\"⇕\\\",\\\"UpEquilibrium\\\":\\\"⥮\\\",\\\"upharpoonleft\\\":\\\"↿\\\",\\\"upharpoonright\\\":\\\"↾\\\",\\\"uplus\\\":\\\"⊎\\\",\\\"UpperLeftArrow\\\":\\\"↖\\\",\\\"UpperRightArrow\\\":\\\"↗\\\",\\\"upsi\\\":\\\"υ\\\",\\\"Upsi\\\":\\\"ϒ\\\",\\\"upsih\\\":\\\"ϒ\\\",\\\"Upsilon\\\":\\\"Υ\\\",\\\"upsilon\\\":\\\"υ\\\",\\\"UpTeeArrow\\\":\\\"↥\\\",\\\"UpTee\\\":\\\"⊥\\\",\\\"upuparrows\\\":\\\"⇈\\\",\\\"urcorn\\\":\\\"⌝\\\",\\\"urcorner\\\":\\\"⌝\\\",\\\"urcrop\\\":\\\"⌎\\\",\\\"Uring\\\":\\\"Ů\\\",\\\"uring\\\":\\\"ů\\\",\\\"urtri\\\":\\\"◹\\\",\\\"Uscr\\\":\\\"𝒰\\\",\\\"uscr\\\":\\\"𝓊\\\",\\\"utdot\\\":\\\"⋰\\\",\\\"Utilde\\\":\\\"Ũ\\\",\\\"utilde\\\":\\\"ũ\\\",\\\"utri\\\":\\\"▵\\\",\\\"utrif\\\":\\\"▴\\\",\\\"uuarr\\\":\\\"⇈\\\",\\\"Uuml\\\":\\\"Ü\\\",\\\"uuml\\\":\\\"ü\\\",\\\"uwangle\\\":\\\"⦧\\\",\\\"vangrt\\\":\\\"⦜\\\",\\\"varepsilon\\\":\\\"ϵ\\\",\\\"varkappa\\\":\\\"ϰ\\\",\\\"varnothing\\\":\\\"∅\\\",\\\"varphi\\\":\\\"ϕ\\\",\\\"varpi\\\":\\\"ϖ\\\",\\\"varpropto\\\":\\\"∝\\\",\\\"varr\\\":\\\"↕\\\",\\\"vArr\\\":\\\"⇕\\\",\\\"varrho\\\":\\\"ϱ\\\",\\\"varsigma\\\":\\\"ς\\\",\\\"varsubsetneq\\\":\\\"⊊︀\\\",\\\"varsubsetneqq\\\":\\\"⫋︀\\\",\\\"varsupsetneq\\\":\\\"⊋︀\\\",\\\"varsupsetneqq\\\":\\\"⫌︀\\\",\\\"vartheta\\\":\\\"ϑ\\\",\\\"vartriangleleft\\\":\\\"⊲\\\",\\\"vartriangleright\\\":\\\"⊳\\\",\\\"vBar\\\":\\\"⫨\\\",\\\"Vbar\\\":\\\"⫫\\\",\\\"vBarv\\\":\\\"⫩\\\",\\\"Vcy\\\":\\\"В\\\",\\\"vcy\\\":\\\"в\\\",\\\"vdash\\\":\\\"⊢\\\",\\\"vDash\\\":\\\"⊨\\\",\\\"Vdash\\\":\\\"⊩\\\",\\\"VDash\\\":\\\"⊫\\\",\\\"Vdashl\\\":\\\"⫦\\\",\\\"veebar\\\":\\\"⊻\\\",\\\"vee\\\":\\\"∨\\\",\\\"Vee\\\":\\\"⋁\\\",\\\"veeeq\\\":\\\"≚\\\",\\\"vellip\\\":\\\"⋮\\\",\\\"verbar\\\":\\\"|\\\",\\\"Verbar\\\":\\\"‖\\\",\\\"vert\\\":\\\"|\\\",\\\"Vert\\\":\\\"‖\\\",\\\"VerticalBar\\\":\\\"∣\\\",\\\"VerticalLine\\\":\\\"|\\\",\\\"VerticalSeparator\\\":\\\"❘\\\",\\\"VerticalTilde\\\":\\\"≀\\\",\\\"VeryThinSpace\\\":\\\" \\\",\\\"Vfr\\\":\\\"𝔙\\\",\\\"vfr\\\":\\\"𝔳\\\",\\\"vltri\\\":\\\"⊲\\\",\\\"vnsub\\\":\\\"⊂⃒\\\",\\\"vnsup\\\":\\\"⊃⃒\\\",\\\"Vopf\\\":\\\"𝕍\\\",\\\"vopf\\\":\\\"𝕧\\\",\\\"vprop\\\":\\\"∝\\\",\\\"vrtri\\\":\\\"⊳\\\",\\\"Vscr\\\":\\\"𝒱\\\",\\\"vscr\\\":\\\"𝓋\\\",\\\"vsubnE\\\":\\\"⫋︀\\\",\\\"vsubne\\\":\\\"⊊︀\\\",\\\"vsupnE\\\":\\\"⫌︀\\\",\\\"vsupne\\\":\\\"⊋︀\\\",\\\"Vvdash\\\":\\\"⊪\\\",\\\"vzigzag\\\":\\\"⦚\\\",\\\"Wcirc\\\":\\\"Ŵ\\\",\\\"wcirc\\\":\\\"ŵ\\\",\\\"wedbar\\\":\\\"⩟\\\",\\\"wedge\\\":\\\"∧\\\",\\\"Wedge\\\":\\\"⋀\\\",\\\"wedgeq\\\":\\\"≙\\\",\\\"weierp\\\":\\\"℘\\\",\\\"Wfr\\\":\\\"𝔚\\\",\\\"wfr\\\":\\\"𝔴\\\",\\\"Wopf\\\":\\\"𝕎\\\",\\\"wopf\\\":\\\"𝕨\\\",\\\"wp\\\":\\\"℘\\\",\\\"wr\\\":\\\"≀\\\",\\\"wreath\\\":\\\"≀\\\",\\\"Wscr\\\":\\\"𝒲\\\",\\\"wscr\\\":\\\"𝓌\\\",\\\"xcap\\\":\\\"⋂\\\",\\\"xcirc\\\":\\\"◯\\\",\\\"xcup\\\":\\\"⋃\\\",\\\"xdtri\\\":\\\"▽\\\",\\\"Xfr\\\":\\\"𝔛\\\",\\\"xfr\\\":\\\"𝔵\\\",\\\"xharr\\\":\\\"⟷\\\",\\\"xhArr\\\":\\\"⟺\\\",\\\"Xi\\\":\\\"Ξ\\\",\\\"xi\\\":\\\"ξ\\\",\\\"xlarr\\\":\\\"⟵\\\",\\\"xlArr\\\":\\\"⟸\\\",\\\"xmap\\\":\\\"⟼\\\",\\\"xnis\\\":\\\"⋻\\\",\\\"xodot\\\":\\\"⨀\\\",\\\"Xopf\\\":\\\"𝕏\\\",\\\"xopf\\\":\\\"𝕩\\\",\\\"xoplus\\\":\\\"⨁\\\",\\\"xotime\\\":\\\"⨂\\\",\\\"xrarr\\\":\\\"⟶\\\",\\\"xrArr\\\":\\\"⟹\\\",\\\"Xscr\\\":\\\"𝒳\\\",\\\"xscr\\\":\\\"𝓍\\\",\\\"xsqcup\\\":\\\"⨆\\\",\\\"xuplus\\\":\\\"⨄\\\",\\\"xutri\\\":\\\"△\\\",\\\"xvee\\\":\\\"⋁\\\",\\\"xwedge\\\":\\\"⋀\\\",\\\"Yacute\\\":\\\"Ý\\\",\\\"yacute\\\":\\\"ý\\\",\\\"YAcy\\\":\\\"Я\\\",\\\"yacy\\\":\\\"я\\\",\\\"Ycirc\\\":\\\"Ŷ\\\",\\\"ycirc\\\":\\\"ŷ\\\",\\\"Ycy\\\":\\\"Ы\\\",\\\"ycy\\\":\\\"ы\\\",\\\"yen\\\":\\\"¥\\\",\\\"Yfr\\\":\\\"𝔜\\\",\\\"yfr\\\":\\\"𝔶\\\",\\\"YIcy\\\":\\\"Ї\\\",\\\"yicy\\\":\\\"ї\\\",\\\"Yopf\\\":\\\"𝕐\\\",\\\"yopf\\\":\\\"𝕪\\\",\\\"Yscr\\\":\\\"𝒴\\\",\\\"yscr\\\":\\\"𝓎\\\",\\\"YUcy\\\":\\\"Ю\\\",\\\"yucy\\\":\\\"ю\\\",\\\"yuml\\\":\\\"ÿ\\\",\\\"Yuml\\\":\\\"Ÿ\\\",\\\"Zacute\\\":\\\"Ź\\\",\\\"zacute\\\":\\\"ź\\\",\\\"Zcaron\\\":\\\"Ž\\\",\\\"zcaron\\\":\\\"ž\\\",\\\"Zcy\\\":\\\"З\\\",\\\"zcy\\\":\\\"з\\\",\\\"Zdot\\\":\\\"Ż\\\",\\\"zdot\\\":\\\"ż\\\",\\\"zeetrf\\\":\\\"ℨ\\\",\\\"ZeroWidthSpace\\\":\\\"​\\\",\\\"Zeta\\\":\\\"Ζ\\\",\\\"zeta\\\":\\\"ζ\\\",\\\"zfr\\\":\\\"𝔷\\\",\\\"Zfr\\\":\\\"ℨ\\\",\\\"ZHcy\\\":\\\"Ж\\\",\\\"zhcy\\\":\\\"ж\\\",\\\"zigrarr\\\":\\\"⇝\\\",\\\"zopf\\\":\\\"𝕫\\\",\\\"Zopf\\\":\\\"ℤ\\\",\\\"Zscr\\\":\\\"𝒵\\\",\\\"zscr\\\":\\\"𝓏\\\",\\\"zwj\\\":\\\"‍\\\",\\\"zwnj\\\":\\\"‌\\\"}\");\n\n//# sourceURL=webpack:///./node_modules/entities/lib/maps/entities.json?"); - -/***/ }), - -/***/ "./node_modules/linkify-it/index.js": -/*!******************************************!*\ - !*** ./node_modules/linkify-it/index.js ***! - \******************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("\n\n\n////////////////////////////////////////////////////////////////////////////////\n// Helpers\n\n// Merge objects\n//\nfunction assign(obj /*from1, from2, from3, ...*/) {\n var sources = Array.prototype.slice.call(arguments, 1);\n\n sources.forEach(function (source) {\n if (!source) { return; }\n\n Object.keys(source).forEach(function (key) {\n obj[key] = source[key];\n });\n });\n\n return obj;\n}\n\nfunction _class(obj) { return Object.prototype.toString.call(obj); }\nfunction isString(obj) { return _class(obj) === '[object String]'; }\nfunction isObject(obj) { return _class(obj) === '[object Object]'; }\nfunction isRegExp(obj) { return _class(obj) === '[object RegExp]'; }\nfunction isFunction(obj) { return _class(obj) === '[object Function]'; }\n\n\nfunction escapeRE(str) { return str.replace(/[.?*+^$[\\]\\\\(){}|-]/g, '\\\\$&'); }\n\n////////////////////////////////////////////////////////////////////////////////\n\n\nvar defaultOptions = {\n fuzzyLink: true,\n fuzzyEmail: true,\n fuzzyIP: false\n};\n\n\nfunction isOptionsObj(obj) {\n return Object.keys(obj || {}).reduce(function (acc, k) {\n return acc || defaultOptions.hasOwnProperty(k);\n }, false);\n}\n\n\nvar defaultSchemas = {\n 'http:': {\n validate: function (text, pos, self) {\n var tail = text.slice(pos);\n\n if (!self.re.http) {\n // compile lazily, because \"host\"-containing variables can change on tlds update.\n self.re.http = new RegExp(\n '^\\\\/\\\\/' + self.re.src_auth + self.re.src_host_port_strict + self.re.src_path, 'i'\n );\n }\n if (self.re.http.test(tail)) {\n return tail.match(self.re.http)[0].length;\n }\n return 0;\n }\n },\n 'https:': 'http:',\n 'ftp:': 'http:',\n '//': {\n validate: function (text, pos, self) {\n var tail = text.slice(pos);\n\n if (!self.re.no_http) {\n // compile lazily, because \"host\"-containing variables can change on tlds update.\n self.re.no_http = new RegExp(\n '^' +\n self.re.src_auth +\n // Don't allow single-level domains, because of false positives like '//test'\n // with code comments\n '(?:localhost|(?:(?:' + self.re.src_domain + ')\\\\.)+' + self.re.src_domain_root + ')' +\n self.re.src_port +\n self.re.src_host_terminator +\n self.re.src_path,\n\n 'i'\n );\n }\n\n if (self.re.no_http.test(tail)) {\n // should not be `://` & `///`, that protects from errors in protocol name\n if (pos >= 3 && text[pos - 3] === ':') { return 0; }\n if (pos >= 3 && text[pos - 3] === '/') { return 0; }\n return tail.match(self.re.no_http)[0].length;\n }\n return 0;\n }\n },\n 'mailto:': {\n validate: function (text, pos, self) {\n var tail = text.slice(pos);\n\n if (!self.re.mailto) {\n self.re.mailto = new RegExp(\n '^' + self.re.src_email_name + '@' + self.re.src_host_strict, 'i'\n );\n }\n if (self.re.mailto.test(tail)) {\n return tail.match(self.re.mailto)[0].length;\n }\n return 0;\n }\n }\n};\n\n/*eslint-disable max-len*/\n\n// RE pattern for 2-character tlds (autogenerated by ./support/tlds_2char_gen.js)\nvar tlds_2ch_src_re = 'a[cdefgilmnoqrstuwxz]|b[abdefghijmnorstvwyz]|c[acdfghiklmnoruvwxyz]|d[ejkmoz]|e[cegrstu]|f[ijkmor]|g[abdefghilmnpqrstuwy]|h[kmnrtu]|i[delmnoqrst]|j[emop]|k[eghimnprwyz]|l[abcikrstuvy]|m[acdeghklmnopqrstuvwxyz]|n[acefgilopruz]|om|p[aefghklmnrstwy]|qa|r[eosuw]|s[abcdeghijklmnortuvxyz]|t[cdfghjklmnortvwz]|u[agksyz]|v[aceginu]|w[fs]|y[et]|z[amw]';\n\n// DON'T try to make PRs with changes. Extend TLDs with LinkifyIt.tlds() instead\nvar tlds_default = 'biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|рф'.split('|');\n\n/*eslint-enable max-len*/\n\n////////////////////////////////////////////////////////////////////////////////\n\nfunction resetScanCache(self) {\n self.__index__ = -1;\n self.__text_cache__ = '';\n}\n\nfunction createValidator(re) {\n return function (text, pos) {\n var tail = text.slice(pos);\n\n if (re.test(tail)) {\n return tail.match(re)[0].length;\n }\n return 0;\n };\n}\n\nfunction createNormalizer() {\n return function (match, self) {\n self.normalize(match);\n };\n}\n\n// Schemas compiler. Build regexps.\n//\nfunction compile(self) {\n\n // Load & clone RE patterns.\n var re = self.re = __webpack_require__(/*! ./lib/re */ \"./node_modules/linkify-it/lib/re.js\")(self.__opts__);\n\n // Define dynamic patterns\n var tlds = self.__tlds__.slice();\n\n self.onCompile();\n\n if (!self.__tlds_replaced__) {\n tlds.push(tlds_2ch_src_re);\n }\n tlds.push(re.src_xn);\n\n re.src_tlds = tlds.join('|');\n\n function untpl(tpl) { return tpl.replace('%TLDS%', re.src_tlds); }\n\n re.email_fuzzy = RegExp(untpl(re.tpl_email_fuzzy), 'i');\n re.link_fuzzy = RegExp(untpl(re.tpl_link_fuzzy), 'i');\n re.link_no_ip_fuzzy = RegExp(untpl(re.tpl_link_no_ip_fuzzy), 'i');\n re.host_fuzzy_test = RegExp(untpl(re.tpl_host_fuzzy_test), 'i');\n\n //\n // Compile each schema\n //\n\n var aliases = [];\n\n self.__compiled__ = {}; // Reset compiled data\n\n function schemaError(name, val) {\n throw new Error('(LinkifyIt) Invalid schema \"' + name + '\": ' + val);\n }\n\n Object.keys(self.__schemas__).forEach(function (name) {\n var val = self.__schemas__[name];\n\n // skip disabled methods\n if (val === null) { return; }\n\n var compiled = { validate: null, link: null };\n\n self.__compiled__[name] = compiled;\n\n if (isObject(val)) {\n if (isRegExp(val.validate)) {\n compiled.validate = createValidator(val.validate);\n } else if (isFunction(val.validate)) {\n compiled.validate = val.validate;\n } else {\n schemaError(name, val);\n }\n\n if (isFunction(val.normalize)) {\n compiled.normalize = val.normalize;\n } else if (!val.normalize) {\n compiled.normalize = createNormalizer();\n } else {\n schemaError(name, val);\n }\n\n return;\n }\n\n if (isString(val)) {\n aliases.push(name);\n return;\n }\n\n schemaError(name, val);\n });\n\n //\n // Compile postponed aliases\n //\n\n aliases.forEach(function (alias) {\n if (!self.__compiled__[self.__schemas__[alias]]) {\n // Silently fail on missed schemas to avoid errons on disable.\n // schemaError(alias, self.__schemas__[alias]);\n return;\n }\n\n self.__compiled__[alias].validate =\n self.__compiled__[self.__schemas__[alias]].validate;\n self.__compiled__[alias].normalize =\n self.__compiled__[self.__schemas__[alias]].normalize;\n });\n\n //\n // Fake record for guessed links\n //\n self.__compiled__[''] = { validate: null, normalize: createNormalizer() };\n\n //\n // Build schema condition\n //\n var slist = Object.keys(self.__compiled__)\n .filter(function (name) {\n // Filter disabled & fake schemas\n return name.length > 0 && self.__compiled__[name];\n })\n .map(escapeRE)\n .join('|');\n // (?!_) cause 1.5x slowdown\n self.re.schema_test = RegExp('(^|(?!_)(?:[><\\uff5c]|' + re.src_ZPCc + '))(' + slist + ')', 'i');\n self.re.schema_search = RegExp('(^|(?!_)(?:[><\\uff5c]|' + re.src_ZPCc + '))(' + slist + ')', 'ig');\n\n self.re.pretest = RegExp(\n '(' + self.re.schema_test.source + ')|(' + self.re.host_fuzzy_test.source + ')|@',\n 'i'\n );\n\n //\n // Cleanup\n //\n\n resetScanCache(self);\n}\n\n/**\n * class Match\n *\n * Match result. Single element of array, returned by [[LinkifyIt#match]]\n **/\nfunction Match(self, shift) {\n var start = self.__index__,\n end = self.__last_index__,\n text = self.__text_cache__.slice(start, end);\n\n /**\n * Match#schema -> String\n *\n * Prefix (protocol) for matched string.\n **/\n this.schema = self.__schema__.toLowerCase();\n /**\n * Match#index -> Number\n *\n * First position of matched string.\n **/\n this.index = start + shift;\n /**\n * Match#lastIndex -> Number\n *\n * Next position after matched string.\n **/\n this.lastIndex = end + shift;\n /**\n * Match#raw -> String\n *\n * Matched string.\n **/\n this.raw = text;\n /**\n * Match#text -> String\n *\n * Notmalized text of matched string.\n **/\n this.text = text;\n /**\n * Match#url -> String\n *\n * Normalized url of matched string.\n **/\n this.url = text;\n}\n\nfunction createMatch(self, shift) {\n var match = new Match(self, shift);\n\n self.__compiled__[match.schema].normalize(match, self);\n\n return match;\n}\n\n\n/**\n * class LinkifyIt\n **/\n\n/**\n * new LinkifyIt(schemas, options)\n * - schemas (Object): Optional. Additional schemas to validate (prefix/validator)\n * - options (Object): { fuzzyLink|fuzzyEmail|fuzzyIP: true|false }\n *\n * Creates new linkifier instance with optional additional schemas.\n * Can be called without `new` keyword for convenience.\n *\n * By default understands:\n *\n * - `http(s)://...` , `ftp://...`, `mailto:...` & `//...` links\n * - \"fuzzy\" links and emails (example.com, foo@bar.com).\n *\n * `schemas` is an object, where each key/value describes protocol/rule:\n *\n * - __key__ - link prefix (usually, protocol name with `:` at the end, `skype:`\n * for example). `linkify-it` makes shure that prefix is not preceeded with\n * alphanumeric char and symbols. Only whitespaces and punctuation allowed.\n * - __value__ - rule to check tail after link prefix\n * - _String_ - just alias to existing rule\n * - _Object_\n * - _validate_ - validator function (should return matched length on success),\n * or `RegExp`.\n * - _normalize_ - optional function to normalize text & url of matched result\n * (for example, for @twitter mentions).\n *\n * `options`:\n *\n * - __fuzzyLink__ - recognige URL-s without `http(s):` prefix. Default `true`.\n * - __fuzzyIP__ - allow IPs in fuzzy links above. Can conflict with some texts\n * like version numbers. Default `false`.\n * - __fuzzyEmail__ - recognize emails without `mailto:` prefix.\n *\n **/\nfunction LinkifyIt(schemas, options) {\n if (!(this instanceof LinkifyIt)) {\n return new LinkifyIt(schemas, options);\n }\n\n if (!options) {\n if (isOptionsObj(schemas)) {\n options = schemas;\n schemas = {};\n }\n }\n\n this.__opts__ = assign({}, defaultOptions, options);\n\n // Cache last tested result. Used to skip repeating steps on next `match` call.\n this.__index__ = -1;\n this.__last_index__ = -1; // Next scan position\n this.__schema__ = '';\n this.__text_cache__ = '';\n\n this.__schemas__ = assign({}, defaultSchemas, schemas);\n this.__compiled__ = {};\n\n this.__tlds__ = tlds_default;\n this.__tlds_replaced__ = false;\n\n this.re = {};\n\n compile(this);\n}\n\n\n/** chainable\n * LinkifyIt#add(schema, definition)\n * - schema (String): rule name (fixed pattern prefix)\n * - definition (String|RegExp|Object): schema definition\n *\n * Add new rule definition. See constructor description for details.\n **/\nLinkifyIt.prototype.add = function add(schema, definition) {\n this.__schemas__[schema] = definition;\n compile(this);\n return this;\n};\n\n\n/** chainable\n * LinkifyIt#set(options)\n * - options (Object): { fuzzyLink|fuzzyEmail|fuzzyIP: true|false }\n *\n * Set recognition options for links without schema.\n **/\nLinkifyIt.prototype.set = function set(options) {\n this.__opts__ = assign(this.__opts__, options);\n return this;\n};\n\n\n/**\n * LinkifyIt#test(text) -> Boolean\n *\n * Searches linkifiable pattern and returns `true` on success or `false` on fail.\n **/\nLinkifyIt.prototype.test = function test(text) {\n // Reset scan cache\n this.__text_cache__ = text;\n this.__index__ = -1;\n\n if (!text.length) { return false; }\n\n var m, ml, me, len, shift, next, re, tld_pos, at_pos;\n\n // try to scan for link with schema - that's the most simple rule\n if (this.re.schema_test.test(text)) {\n re = this.re.schema_search;\n re.lastIndex = 0;\n while ((m = re.exec(text)) !== null) {\n len = this.testSchemaAt(text, m[2], re.lastIndex);\n if (len) {\n this.__schema__ = m[2];\n this.__index__ = m.index + m[1].length;\n this.__last_index__ = m.index + m[0].length + len;\n break;\n }\n }\n }\n\n if (this.__opts__.fuzzyLink && this.__compiled__['http:']) {\n // guess schemaless links\n tld_pos = text.search(this.re.host_fuzzy_test);\n if (tld_pos >= 0) {\n // if tld is located after found link - no need to check fuzzy pattern\n if (this.__index__ < 0 || tld_pos < this.__index__) {\n if ((ml = text.match(this.__opts__.fuzzyIP ? this.re.link_fuzzy : this.re.link_no_ip_fuzzy)) !== null) {\n\n shift = ml.index + ml[1].length;\n\n if (this.__index__ < 0 || shift < this.__index__) {\n this.__schema__ = '';\n this.__index__ = shift;\n this.__last_index__ = ml.index + ml[0].length;\n }\n }\n }\n }\n }\n\n if (this.__opts__.fuzzyEmail && this.__compiled__['mailto:']) {\n // guess schemaless emails\n at_pos = text.indexOf('@');\n if (at_pos >= 0) {\n // We can't skip this check, because this cases are possible:\n // 192.168.1.1@gmail.com, my.in@example.com\n if ((me = text.match(this.re.email_fuzzy)) !== null) {\n\n shift = me.index + me[1].length;\n next = me.index + me[0].length;\n\n if (this.__index__ < 0 || shift < this.__index__ ||\n (shift === this.__index__ && next > this.__last_index__)) {\n this.__schema__ = 'mailto:';\n this.__index__ = shift;\n this.__last_index__ = next;\n }\n }\n }\n }\n\n return this.__index__ >= 0;\n};\n\n\n/**\n * LinkifyIt#pretest(text) -> Boolean\n *\n * Very quick check, that can give false positives. Returns true if link MAY BE\n * can exists. Can be used for speed optimization, when you need to check that\n * link NOT exists.\n **/\nLinkifyIt.prototype.pretest = function pretest(text) {\n return this.re.pretest.test(text);\n};\n\n\n/**\n * LinkifyIt#testSchemaAt(text, name, position) -> Number\n * - text (String): text to scan\n * - name (String): rule (schema) name\n * - position (Number): text offset to check from\n *\n * Similar to [[LinkifyIt#test]] but checks only specific protocol tail exactly\n * at given position. Returns length of found pattern (0 on fail).\n **/\nLinkifyIt.prototype.testSchemaAt = function testSchemaAt(text, schema, pos) {\n // If not supported schema check requested - terminate\n if (!this.__compiled__[schema.toLowerCase()]) {\n return 0;\n }\n return this.__compiled__[schema.toLowerCase()].validate(text, pos, this);\n};\n\n\n/**\n * LinkifyIt#match(text) -> Array|null\n *\n * Returns array of found link descriptions or `null` on fail. We strongly\n * recommend to use [[LinkifyIt#test]] first, for best speed.\n *\n * ##### Result match description\n *\n * - __schema__ - link schema, can be empty for fuzzy links, or `//` for\n * protocol-neutral links.\n * - __index__ - offset of matched text\n * - __lastIndex__ - index of next char after mathch end\n * - __raw__ - matched text\n * - __text__ - normalized text\n * - __url__ - link, generated from matched text\n **/\nLinkifyIt.prototype.match = function match(text) {\n var shift = 0, result = [];\n\n // Try to take previous element from cache, if .test() called before\n if (this.__index__ >= 0 && this.__text_cache__ === text) {\n result.push(createMatch(this, shift));\n shift = this.__last_index__;\n }\n\n // Cut head if cache was used\n var tail = shift ? text.slice(shift) : text;\n\n // Scan string until end reached\n while (this.test(tail)) {\n result.push(createMatch(this, shift));\n\n tail = tail.slice(this.__last_index__);\n shift += this.__last_index__;\n }\n\n if (result.length) {\n return result;\n }\n\n return null;\n};\n\n\n/** chainable\n * LinkifyIt#tlds(list [, keepOld]) -> this\n * - list (Array): list of tlds\n * - keepOld (Boolean): merge with current list if `true` (`false` by default)\n *\n * Load (or merge) new tlds list. Those are user for fuzzy links (without prefix)\n * to avoid false positives. By default this algorythm used:\n *\n * - hostname with any 2-letter root zones are ok.\n * - biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|рф\n * are ok.\n * - encoded (`xn--...`) root zones are ok.\n *\n * If list is replaced, then exact match for 2-chars root zones will be checked.\n **/\nLinkifyIt.prototype.tlds = function tlds(list, keepOld) {\n list = Array.isArray(list) ? list : [ list ];\n\n if (!keepOld) {\n this.__tlds__ = list.slice();\n this.__tlds_replaced__ = true;\n compile(this);\n return this;\n }\n\n this.__tlds__ = this.__tlds__.concat(list)\n .sort()\n .filter(function (el, idx, arr) {\n return el !== arr[idx - 1];\n })\n .reverse();\n\n compile(this);\n return this;\n};\n\n/**\n * LinkifyIt#normalize(match)\n *\n * Default normalizer (if schema does not define it's own).\n **/\nLinkifyIt.prototype.normalize = function normalize(match) {\n\n // Do minimal possible changes by default. Need to collect feedback prior\n // to move forward https://github.com/markdown-it/linkify-it/issues/1\n\n if (!match.schema) { match.url = 'http://' + match.url; }\n\n if (match.schema === 'mailto:' && !/^mailto:/i.test(match.url)) {\n match.url = 'mailto:' + match.url;\n }\n};\n\n\n/**\n * LinkifyIt#onCompile()\n *\n * Override to modify basic RegExp-s.\n **/\nLinkifyIt.prototype.onCompile = function onCompile() {\n};\n\n\nmodule.exports = LinkifyIt;\n\n\n//# sourceURL=webpack:///./node_modules/linkify-it/index.js?"); - -/***/ }), - -/***/ "./node_modules/linkify-it/lib/re.js": -/*!*******************************************!*\ - !*** ./node_modules/linkify-it/lib/re.js ***! - \*******************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("\n\n\nmodule.exports = function (opts) {\n var re = {};\n\n // Use direct extract instead of `regenerate` to reduse browserified size\n re.src_Any = __webpack_require__(/*! uc.micro/properties/Any/regex */ \"./node_modules/linkify-it/node_modules/uc.micro/properties/Any/regex.js\").source;\n re.src_Cc = __webpack_require__(/*! uc.micro/categories/Cc/regex */ \"./node_modules/linkify-it/node_modules/uc.micro/categories/Cc/regex.js\").source;\n re.src_Z = __webpack_require__(/*! uc.micro/categories/Z/regex */ \"./node_modules/linkify-it/node_modules/uc.micro/categories/Z/regex.js\").source;\n re.src_P = __webpack_require__(/*! uc.micro/categories/P/regex */ \"./node_modules/linkify-it/node_modules/uc.micro/categories/P/regex.js\").source;\n\n // \\p{\\Z\\P\\Cc\\CF} (white spaces + control + format + punctuation)\n re.src_ZPCc = [ re.src_Z, re.src_P, re.src_Cc ].join('|');\n\n // \\p{\\Z\\Cc} (white spaces + control)\n re.src_ZCc = [ re.src_Z, re.src_Cc ].join('|');\n\n // Experimental. List of chars, completely prohibited in links\n // because can separate it from other part of text\n var text_separators = '[><\\uff5c]';\n\n // All possible word characters (everything without punctuation, spaces & controls)\n // Defined via punctuation & spaces to save space\n // Should be something like \\p{\\L\\N\\S\\M} (\\w but without `_`)\n re.src_pseudo_letter = '(?:(?!' + text_separators + '|' + re.src_ZPCc + ')' + re.src_Any + ')';\n // The same as abothe but without [0-9]\n // var src_pseudo_letter_non_d = '(?:(?![0-9]|' + src_ZPCc + ')' + src_Any + ')';\n\n ////////////////////////////////////////////////////////////////////////////////\n\n re.src_ip4 =\n\n '(?:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)';\n\n // Prohibit any of \"@/[]()\" in user/pass to avoid wrong domain fetch.\n re.src_auth = '(?:(?:(?!' + re.src_ZCc + '|[@/\\\\[\\\\]()]).)+@)?';\n\n re.src_port =\n\n '(?::(?:6(?:[0-4]\\\\d{3}|5(?:[0-4]\\\\d{2}|5(?:[0-2]\\\\d|3[0-5])))|[1-5]?\\\\d{1,4}))?';\n\n re.src_host_terminator =\n\n '(?=$|' + text_separators + '|' + re.src_ZPCc + ')(?!-|_|:\\\\d|\\\\.-|\\\\.(?!$|' + re.src_ZPCc + '))';\n\n re.src_path =\n\n '(?:' +\n '[/?#]' +\n '(?:' +\n '(?!' + re.src_ZCc + '|' + text_separators + '|[()[\\\\]{}.,\"\\'?!\\\\-]).|' +\n '\\\\[(?:(?!' + re.src_ZCc + '|\\\\]).)*\\\\]|' +\n '\\\\((?:(?!' + re.src_ZCc + '|[)]).)*\\\\)|' +\n '\\\\{(?:(?!' + re.src_ZCc + '|[}]).)*\\\\}|' +\n '\\\\\"(?:(?!' + re.src_ZCc + '|[\"]).)+\\\\\"|' +\n \"\\\\'(?:(?!\" + re.src_ZCc + \"|[']).)+\\\\'|\" +\n \"\\\\'(?=\" + re.src_pseudo_letter + '|[-]).|' + // allow `I'm_king` if no pair found\n '\\\\.{2,}[a-zA-Z0-9%/&]|' + // google has many dots in \"google search\" links (#66, #81).\n // github has ... in commit range links,\n // Restrict to\n // - english\n // - percent-encoded\n // - parts of file path\n // - params separator\n // until more examples found.\n '\\\\.(?!' + re.src_ZCc + '|[.]).|' +\n (opts && opts['---'] ?\n '\\\\-(?!--(?:[^-]|$))(?:-*)|' // `---` => long dash, terminate\n :\n '\\\\-+|'\n ) +\n '\\\\,(?!' + re.src_ZCc + ').|' + // allow `,,,` in paths\n '\\\\!+(?!' + re.src_ZCc + '|[!]).|' + // allow `!!!` in paths, but not at the end\n '\\\\?(?!' + re.src_ZCc + '|[?]).' +\n ')+' +\n '|\\\\/' +\n ')?';\n\n // Allow anything in markdown spec, forbid quote (\") at the first position\n // because emails enclosed in quotes are far more common\n re.src_email_name =\n\n '[\\\\-;:&=\\\\+\\\\$,\\\\.a-zA-Z0-9_][\\\\-;:&=\\\\+\\\\$,\\\\\"\\\\.a-zA-Z0-9_]*';\n\n re.src_xn =\n\n 'xn--[a-z0-9\\\\-]{1,59}';\n\n // More to read about domain names\n // http://serverfault.com/questions/638260/\n\n re.src_domain_root =\n\n // Allow letters & digits (http://test1)\n '(?:' +\n re.src_xn +\n '|' +\n re.src_pseudo_letter + '{1,63}' +\n ')';\n\n re.src_domain =\n\n '(?:' +\n re.src_xn +\n '|' +\n '(?:' + re.src_pseudo_letter + ')' +\n '|' +\n '(?:' + re.src_pseudo_letter + '(?:-|' + re.src_pseudo_letter + '){0,61}' + re.src_pseudo_letter + ')' +\n ')';\n\n re.src_host =\n\n '(?:' +\n // Don't need IP check, because digits are already allowed in normal domain names\n // src_ip4 +\n // '|' +\n '(?:(?:(?:' + re.src_domain + ')\\\\.)*' + re.src_domain/*_root*/ + ')' +\n ')';\n\n re.tpl_host_fuzzy =\n\n '(?:' +\n re.src_ip4 +\n '|' +\n '(?:(?:(?:' + re.src_domain + ')\\\\.)+(?:%TLDS%))' +\n ')';\n\n re.tpl_host_no_ip_fuzzy =\n\n '(?:(?:(?:' + re.src_domain + ')\\\\.)+(?:%TLDS%))';\n\n re.src_host_strict =\n\n re.src_host + re.src_host_terminator;\n\n re.tpl_host_fuzzy_strict =\n\n re.tpl_host_fuzzy + re.src_host_terminator;\n\n re.src_host_port_strict =\n\n re.src_host + re.src_port + re.src_host_terminator;\n\n re.tpl_host_port_fuzzy_strict =\n\n re.tpl_host_fuzzy + re.src_port + re.src_host_terminator;\n\n re.tpl_host_port_no_ip_fuzzy_strict =\n\n re.tpl_host_no_ip_fuzzy + re.src_port + re.src_host_terminator;\n\n\n ////////////////////////////////////////////////////////////////////////////////\n // Main rules\n\n // Rude test fuzzy links by host, for quick deny\n re.tpl_host_fuzzy_test =\n\n 'localhost|www\\\\.|\\\\.\\\\d{1,3}\\\\.|(?:\\\\.(?:%TLDS%)(?:' + re.src_ZPCc + '|>|$))';\n\n re.tpl_email_fuzzy =\n\n '(^|' + text_separators + '|\"|\\\\(|' + re.src_ZCc + ')' +\n '(' + re.src_email_name + '@' + re.tpl_host_fuzzy_strict + ')';\n\n re.tpl_link_fuzzy =\n // Fuzzy link can't be prepended with .:/\\- and non punctuation.\n // but can start with > (markdown blockquote)\n '(^|(?![.:/\\\\-_@])(?:[$+<=>^`|\\uff5c]|' + re.src_ZPCc + '))' +\n '((?![$+<=>^`|\\uff5c])' + re.tpl_host_port_fuzzy_strict + re.src_path + ')';\n\n re.tpl_link_no_ip_fuzzy =\n // Fuzzy link can't be prepended with .:/\\- and non punctuation.\n // but can start with > (markdown blockquote)\n '(^|(?![.:/\\\\-_@])(?:[$+<=>^`|\\uff5c]|' + re.src_ZPCc + '))' +\n '((?![$+<=>^`|\\uff5c])' + re.tpl_host_port_no_ip_fuzzy_strict + re.src_path + ')';\n\n return re;\n};\n\n\n//# sourceURL=webpack:///./node_modules/linkify-it/lib/re.js?"); - -/***/ }), - -/***/ "./node_modules/linkify-it/node_modules/uc.micro/categories/Cc/regex.js": -/*!******************************************************************************!*\ - !*** ./node_modules/linkify-it/node_modules/uc.micro/categories/Cc/regex.js ***! - \******************************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -eval("module.exports=/[\\0-\\x1F\\x7F-\\x9F]/\n\n//# sourceURL=webpack:///./node_modules/linkify-it/node_modules/uc.micro/categories/Cc/regex.js?"); - -/***/ }), - -/***/ "./node_modules/linkify-it/node_modules/uc.micro/categories/P/regex.js": -/*!*****************************************************************************!*\ - !*** ./node_modules/linkify-it/node_modules/uc.micro/categories/P/regex.js ***! - \*****************************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -eval("module.exports=/[!-#%-\\*,-/:;\\?@\\[-\\]_\\{\\}\\xA1\\xA7\\xAB\\xB6\\xB7\\xBB\\xBF\\u037E\\u0387\\u055A-\\u055F\\u0589\\u058A\\u05BE\\u05C0\\u05C3\\u05C6\\u05F3\\u05F4\\u0609\\u060A\\u060C\\u060D\\u061B\\u061E\\u061F\\u066A-\\u066D\\u06D4\\u0700-\\u070D\\u07F7-\\u07F9\\u0830-\\u083E\\u085E\\u0964\\u0965\\u0970\\u0AF0\\u0DF4\\u0E4F\\u0E5A\\u0E5B\\u0F04-\\u0F12\\u0F14\\u0F3A-\\u0F3D\\u0F85\\u0FD0-\\u0FD4\\u0FD9\\u0FDA\\u104A-\\u104F\\u10FB\\u1360-\\u1368\\u1400\\u166D\\u166E\\u169B\\u169C\\u16EB-\\u16ED\\u1735\\u1736\\u17D4-\\u17D6\\u17D8-\\u17DA\\u1800-\\u180A\\u1944\\u1945\\u1A1E\\u1A1F\\u1AA0-\\u1AA6\\u1AA8-\\u1AAD\\u1B5A-\\u1B60\\u1BFC-\\u1BFF\\u1C3B-\\u1C3F\\u1C7E\\u1C7F\\u1CC0-\\u1CC7\\u1CD3\\u2010-\\u2027\\u2030-\\u2043\\u2045-\\u2051\\u2053-\\u205E\\u207D\\u207E\\u208D\\u208E\\u2308-\\u230B\\u2329\\u232A\\u2768-\\u2775\\u27C5\\u27C6\\u27E6-\\u27EF\\u2983-\\u2998\\u29D8-\\u29DB\\u29FC\\u29FD\\u2CF9-\\u2CFC\\u2CFE\\u2CFF\\u2D70\\u2E00-\\u2E2E\\u2E30-\\u2E44\\u3001-\\u3003\\u3008-\\u3011\\u3014-\\u301F\\u3030\\u303D\\u30A0\\u30FB\\uA4FE\\uA4FF\\uA60D-\\uA60F\\uA673\\uA67E\\uA6F2-\\uA6F7\\uA874-\\uA877\\uA8CE\\uA8CF\\uA8F8-\\uA8FA\\uA8FC\\uA92E\\uA92F\\uA95F\\uA9C1-\\uA9CD\\uA9DE\\uA9DF\\uAA5C-\\uAA5F\\uAADE\\uAADF\\uAAF0\\uAAF1\\uABEB\\uFD3E\\uFD3F\\uFE10-\\uFE19\\uFE30-\\uFE52\\uFE54-\\uFE61\\uFE63\\uFE68\\uFE6A\\uFE6B\\uFF01-\\uFF03\\uFF05-\\uFF0A\\uFF0C-\\uFF0F\\uFF1A\\uFF1B\\uFF1F\\uFF20\\uFF3B-\\uFF3D\\uFF3F\\uFF5B\\uFF5D\\uFF5F-\\uFF65]|\\uD800[\\uDD00-\\uDD02\\uDF9F\\uDFD0]|\\uD801\\uDD6F|\\uD802[\\uDC57\\uDD1F\\uDD3F\\uDE50-\\uDE58\\uDE7F\\uDEF0-\\uDEF6\\uDF39-\\uDF3F\\uDF99-\\uDF9C]|\\uD804[\\uDC47-\\uDC4D\\uDCBB\\uDCBC\\uDCBE-\\uDCC1\\uDD40-\\uDD43\\uDD74\\uDD75\\uDDC5-\\uDDC9\\uDDCD\\uDDDB\\uDDDD-\\uDDDF\\uDE38-\\uDE3D\\uDEA9]|\\uD805[\\uDC4B-\\uDC4F\\uDC5B\\uDC5D\\uDCC6\\uDDC1-\\uDDD7\\uDE41-\\uDE43\\uDE60-\\uDE6C\\uDF3C-\\uDF3E]|\\uD807[\\uDC41-\\uDC45\\uDC70\\uDC71]|\\uD809[\\uDC70-\\uDC74]|\\uD81A[\\uDE6E\\uDE6F\\uDEF5\\uDF37-\\uDF3B\\uDF44]|\\uD82F\\uDC9F|\\uD836[\\uDE87-\\uDE8B]|\\uD83A[\\uDD5E\\uDD5F]/\n\n//# sourceURL=webpack:///./node_modules/linkify-it/node_modules/uc.micro/categories/P/regex.js?"); - -/***/ }), - -/***/ "./node_modules/linkify-it/node_modules/uc.micro/categories/Z/regex.js": -/*!*****************************************************************************!*\ - !*** ./node_modules/linkify-it/node_modules/uc.micro/categories/Z/regex.js ***! - \*****************************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -eval("module.exports=/[ \\xA0\\u1680\\u2000-\\u200A\\u202F\\u205F\\u3000]/\n\n//# sourceURL=webpack:///./node_modules/linkify-it/node_modules/uc.micro/categories/Z/regex.js?"); - -/***/ }), - -/***/ "./node_modules/linkify-it/node_modules/uc.micro/properties/Any/regex.js": -/*!*******************************************************************************!*\ - !*** ./node_modules/linkify-it/node_modules/uc.micro/properties/Any/regex.js ***! - \*******************************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -eval("module.exports=/[\\0-\\uD7FF\\uE000-\\uFFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]/\n\n//# sourceURL=webpack:///./node_modules/linkify-it/node_modules/uc.micro/properties/Any/regex.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/index.js": -/*!*******************************************!*\ - !*** ./node_modules/markdown-it/index.js ***! - \*******************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("\n\n\nmodule.exports = __webpack_require__(/*! ./lib/ */ \"./node_modules/markdown-it/lib/index.js\");\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/index.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/common/entities.js": -/*!*********************************************************!*\ - !*** ./node_modules/markdown-it/lib/common/entities.js ***! - \*********************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// HTML5 entities map: { name -> utf16string }\n//\n\n\n/*eslint quotes:0*/\nmodule.exports = __webpack_require__(/*! entities/lib/maps/entities.json */ \"./node_modules/entities/lib/maps/entities.json\");\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/common/entities.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/common/html_blocks.js": -/*!************************************************************!*\ - !*** ./node_modules/markdown-it/lib/common/html_blocks.js ***! - \************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// List of valid html blocks names, accorting to commonmark spec\n// http://jgm.github.io/CommonMark/spec.html#html-blocks\n\n\n\n\nmodule.exports = [\n 'address',\n 'article',\n 'aside',\n 'base',\n 'basefont',\n 'blockquote',\n 'body',\n 'caption',\n 'center',\n 'col',\n 'colgroup',\n 'dd',\n 'details',\n 'dialog',\n 'dir',\n 'div',\n 'dl',\n 'dt',\n 'fieldset',\n 'figcaption',\n 'figure',\n 'footer',\n 'form',\n 'frame',\n 'frameset',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'head',\n 'header',\n 'hr',\n 'html',\n 'iframe',\n 'legend',\n 'li',\n 'link',\n 'main',\n 'menu',\n 'menuitem',\n 'nav',\n 'noframes',\n 'ol',\n 'optgroup',\n 'option',\n 'p',\n 'param',\n 'section',\n 'source',\n 'summary',\n 'table',\n 'tbody',\n 'td',\n 'tfoot',\n 'th',\n 'thead',\n 'title',\n 'tr',\n 'track',\n 'ul'\n];\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/common/html_blocks.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/common/html_re.js": -/*!********************************************************!*\ - !*** ./node_modules/markdown-it/lib/common/html_re.js ***! - \********************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Regexps to match html elements\n\n\n\nvar attr_name = '[a-zA-Z_:][a-zA-Z0-9:._-]*';\n\nvar unquoted = '[^\"\\'=<>`\\\\x00-\\\\x20]+';\nvar single_quoted = \"'[^']*'\";\nvar double_quoted = '\"[^\"]*\"';\n\nvar attr_value = '(?:' + unquoted + '|' + single_quoted + '|' + double_quoted + ')';\n\nvar attribute = '(?:\\\\s+' + attr_name + '(?:\\\\s*=\\\\s*' + attr_value + ')?)';\n\nvar open_tag = '<[A-Za-z][A-Za-z0-9\\\\-]*' + attribute + '*\\\\s*\\\\/?>';\n\nvar close_tag = '<\\\\/[A-Za-z][A-Za-z0-9\\\\-]*\\\\s*>';\nvar comment = '|';\nvar processing = '<[?][\\\\s\\\\S]*?[?]>';\nvar declaration = ']*>';\nvar cdata = '';\n\nvar HTML_TAG_RE = new RegExp('^(?:' + open_tag + '|' + close_tag + '|' + comment +\n '|' + processing + '|' + declaration + '|' + cdata + ')');\nvar HTML_OPEN_CLOSE_TAG_RE = new RegExp('^(?:' + open_tag + '|' + close_tag + ')');\n\nmodule.exports.HTML_TAG_RE = HTML_TAG_RE;\nmodule.exports.HTML_OPEN_CLOSE_TAG_RE = HTML_OPEN_CLOSE_TAG_RE;\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/common/html_re.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/common/utils.js": -/*!******************************************************!*\ - !*** ./node_modules/markdown-it/lib/common/utils.js ***! - \******************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Utilities\n//\n\n\n\nfunction _class(obj) { return Object.prototype.toString.call(obj); }\n\nfunction isString(obj) { return _class(obj) === '[object String]'; }\n\nvar _hasOwnProperty = Object.prototype.hasOwnProperty;\n\nfunction has(object, key) {\n return _hasOwnProperty.call(object, key);\n}\n\n// Merge objects\n//\nfunction assign(obj /*from1, from2, from3, ...*/) {\n var sources = Array.prototype.slice.call(arguments, 1);\n\n sources.forEach(function (source) {\n if (!source) { return; }\n\n if (typeof source !== 'object') {\n throw new TypeError(source + 'must be object');\n }\n\n Object.keys(source).forEach(function (key) {\n obj[key] = source[key];\n });\n });\n\n return obj;\n}\n\n// Remove element from array and put another array at those position.\n// Useful for some operations with tokens\nfunction arrayReplaceAt(src, pos, newElements) {\n return [].concat(src.slice(0, pos), newElements, src.slice(pos + 1));\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\nfunction isValidEntityCode(c) {\n /*eslint no-bitwise:0*/\n // broken sequence\n if (c >= 0xD800 && c <= 0xDFFF) { return false; }\n // never used\n if (c >= 0xFDD0 && c <= 0xFDEF) { return false; }\n if ((c & 0xFFFF) === 0xFFFF || (c & 0xFFFF) === 0xFFFE) { return false; }\n // control codes\n if (c >= 0x00 && c <= 0x08) { return false; }\n if (c === 0x0B) { return false; }\n if (c >= 0x0E && c <= 0x1F) { return false; }\n if (c >= 0x7F && c <= 0x9F) { return false; }\n // out of range\n if (c > 0x10FFFF) { return false; }\n return true;\n}\n\nfunction fromCodePoint(c) {\n /*eslint no-bitwise:0*/\n if (c > 0xffff) {\n c -= 0x10000;\n var surrogate1 = 0xd800 + (c >> 10),\n surrogate2 = 0xdc00 + (c & 0x3ff);\n\n return String.fromCharCode(surrogate1, surrogate2);\n }\n return String.fromCharCode(c);\n}\n\n\nvar UNESCAPE_MD_RE = /\\\\([!\"#$%&'()*+,\\-.\\/:;<=>?@[\\\\\\]^_`{|}~])/g;\nvar ENTITY_RE = /&([a-z#][a-z0-9]{1,31});/gi;\nvar UNESCAPE_ALL_RE = new RegExp(UNESCAPE_MD_RE.source + '|' + ENTITY_RE.source, 'gi');\n\nvar DIGITAL_ENTITY_TEST_RE = /^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i;\n\nvar entities = __webpack_require__(/*! ./entities */ \"./node_modules/markdown-it/lib/common/entities.js\");\n\nfunction replaceEntityPattern(match, name) {\n var code = 0;\n\n if (has(entities, name)) {\n return entities[name];\n }\n\n if (name.charCodeAt(0) === 0x23/* # */ && DIGITAL_ENTITY_TEST_RE.test(name)) {\n code = name[1].toLowerCase() === 'x' ?\n parseInt(name.slice(2), 16) : parseInt(name.slice(1), 10);\n\n if (isValidEntityCode(code)) {\n return fromCodePoint(code);\n }\n }\n\n return match;\n}\n\n/*function replaceEntities(str) {\n if (str.indexOf('&') < 0) { return str; }\n\n return str.replace(ENTITY_RE, replaceEntityPattern);\n}*/\n\nfunction unescapeMd(str) {\n if (str.indexOf('\\\\') < 0) { return str; }\n return str.replace(UNESCAPE_MD_RE, '$1');\n}\n\nfunction unescapeAll(str) {\n if (str.indexOf('\\\\') < 0 && str.indexOf('&') < 0) { return str; }\n\n return str.replace(UNESCAPE_ALL_RE, function (match, escaped, entity) {\n if (escaped) { return escaped; }\n return replaceEntityPattern(match, entity);\n });\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\nvar HTML_ESCAPE_TEST_RE = /[&<>\"]/;\nvar HTML_ESCAPE_REPLACE_RE = /[&<>\"]/g;\nvar HTML_REPLACEMENTS = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"'\n};\n\nfunction replaceUnsafeChar(ch) {\n return HTML_REPLACEMENTS[ch];\n}\n\nfunction escapeHtml(str) {\n if (HTML_ESCAPE_TEST_RE.test(str)) {\n return str.replace(HTML_ESCAPE_REPLACE_RE, replaceUnsafeChar);\n }\n return str;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\nvar REGEXP_ESCAPE_RE = /[.?*+^$[\\]\\\\(){}|-]/g;\n\nfunction escapeRE(str) {\n return str.replace(REGEXP_ESCAPE_RE, '\\\\$&');\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\nfunction isSpace(code) {\n switch (code) {\n case 0x09:\n case 0x20:\n return true;\n }\n return false;\n}\n\n// Zs (unicode class) || [\\t\\f\\v\\r\\n]\nfunction isWhiteSpace(code) {\n if (code >= 0x2000 && code <= 0x200A) { return true; }\n switch (code) {\n case 0x09: // \\t\n case 0x0A: // \\n\n case 0x0B: // \\v\n case 0x0C: // \\f\n case 0x0D: // \\r\n case 0x20:\n case 0xA0:\n case 0x1680:\n case 0x202F:\n case 0x205F:\n case 0x3000:\n return true;\n }\n return false;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\n/*eslint-disable max-len*/\nvar UNICODE_PUNCT_RE = __webpack_require__(/*! uc.micro/categories/P/regex */ \"./node_modules/uc.micro/categories/P/regex.js\");\n\n// Currently without astral characters support.\nfunction isPunctChar(ch) {\n return UNICODE_PUNCT_RE.test(ch);\n}\n\n\n// Markdown ASCII punctuation characters.\n//\n// !, \", #, $, %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ?, @, [, \\, ], ^, _, `, {, |, }, or ~\n// http://spec.commonmark.org/0.15/#ascii-punctuation-character\n//\n// Don't confuse with unicode punctuation !!! It lacks some chars in ascii range.\n//\nfunction isMdAsciiPunct(ch) {\n switch (ch) {\n case 0x21/* ! */:\n case 0x22/* \" */:\n case 0x23/* # */:\n case 0x24/* $ */:\n case 0x25/* % */:\n case 0x26/* & */:\n case 0x27/* ' */:\n case 0x28/* ( */:\n case 0x29/* ) */:\n case 0x2A/* * */:\n case 0x2B/* + */:\n case 0x2C/* , */:\n case 0x2D/* - */:\n case 0x2E/* . */:\n case 0x2F/* / */:\n case 0x3A/* : */:\n case 0x3B/* ; */:\n case 0x3C/* < */:\n case 0x3D/* = */:\n case 0x3E/* > */:\n case 0x3F/* ? */:\n case 0x40/* @ */:\n case 0x5B/* [ */:\n case 0x5C/* \\ */:\n case 0x5D/* ] */:\n case 0x5E/* ^ */:\n case 0x5F/* _ */:\n case 0x60/* ` */:\n case 0x7B/* { */:\n case 0x7C/* | */:\n case 0x7D/* } */:\n case 0x7E/* ~ */:\n return true;\n default:\n return false;\n }\n}\n\n// Hepler to unify [reference labels].\n//\nfunction normalizeReference(str) {\n // Trim and collapse whitespace\n //\n str = str.trim().replace(/\\s+/g, ' ');\n\n // In node v10 'ẞ'.toLowerCase() === 'Ṿ', which is presumed to be a bug\n // fixed in v12 (couldn't find any details).\n //\n // So treat this one as a special case\n // (remove this when node v10 is no longer supported).\n //\n if ('ẞ'.toLowerCase() === 'Ṿ') {\n str = str.replace(/ẞ/g, 'ß');\n }\n\n // .toLowerCase().toUpperCase() should get rid of all differences\n // between letter variants.\n //\n // Simple .toLowerCase() doesn't normalize 125 code points correctly,\n // and .toUpperCase doesn't normalize 6 of them (list of exceptions:\n // İ, ϴ, ẞ, Ω, K, Å - those are already uppercased, but have differently\n // uppercased versions).\n //\n // Here's an example showing how it happens. Lets take greek letter omega:\n // uppercase U+0398 (Θ), U+03f4 (ϴ) and lowercase U+03b8 (θ), U+03d1 (ϑ)\n //\n // Unicode entries:\n // 0398;GREEK CAPITAL LETTER THETA;Lu;0;L;;;;;N;;;;03B8;\n // 03B8;GREEK SMALL LETTER THETA;Ll;0;L;;;;;N;;;0398;;0398\n // 03D1;GREEK THETA SYMBOL;Ll;0;L; 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398\n // 03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L; 0398;;;;N;;;;03B8;\n //\n // Case-insensitive comparison should treat all of them as equivalent.\n //\n // But .toLowerCase() doesn't change ϑ (it's already lowercase),\n // and .toUpperCase() doesn't change ϴ (already uppercase).\n //\n // Applying first lower then upper case normalizes any character:\n // '\\u0398\\u03f4\\u03b8\\u03d1'.toLowerCase().toUpperCase() === '\\u0398\\u0398\\u0398\\u0398'\n //\n // Note: this is equivalent to unicode case folding; unicode normalization\n // is a different step that is not required here.\n //\n // Final result should be uppercased, because it's later stored in an object\n // (this avoid a conflict with Object.prototype members,\n // most notably, `__proto__`)\n //\n return str.toLowerCase().toUpperCase();\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\n// Re-export libraries commonly used in both markdown-it and its plugins,\n// so plugins won't have to depend on them explicitly, which reduces their\n// bundled size (e.g. a browser build).\n//\nexports.lib = {};\nexports.lib.mdurl = __webpack_require__(/*! mdurl */ \"./node_modules/mdurl/index.js\");\nexports.lib.ucmicro = __webpack_require__(/*! uc.micro */ \"./node_modules/uc.micro/index.js\");\n\nexports.assign = assign;\nexports.isString = isString;\nexports.has = has;\nexports.unescapeMd = unescapeMd;\nexports.unescapeAll = unescapeAll;\nexports.isValidEntityCode = isValidEntityCode;\nexports.fromCodePoint = fromCodePoint;\n// exports.replaceEntities = replaceEntities;\nexports.escapeHtml = escapeHtml;\nexports.arrayReplaceAt = arrayReplaceAt;\nexports.isSpace = isSpace;\nexports.isWhiteSpace = isWhiteSpace;\nexports.isMdAsciiPunct = isMdAsciiPunct;\nexports.isPunctChar = isPunctChar;\nexports.escapeRE = escapeRE;\nexports.normalizeReference = normalizeReference;\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/common/utils.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/helpers/index.js": -/*!*******************************************************!*\ - !*** ./node_modules/markdown-it/lib/helpers/index.js ***! - \*******************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Just a shortcut for bulk export\n\n\n\nexports.parseLinkLabel = __webpack_require__(/*! ./parse_link_label */ \"./node_modules/markdown-it/lib/helpers/parse_link_label.js\");\nexports.parseLinkDestination = __webpack_require__(/*! ./parse_link_destination */ \"./node_modules/markdown-it/lib/helpers/parse_link_destination.js\");\nexports.parseLinkTitle = __webpack_require__(/*! ./parse_link_title */ \"./node_modules/markdown-it/lib/helpers/parse_link_title.js\");\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/helpers/index.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/helpers/parse_link_destination.js": -/*!************************************************************************!*\ - !*** ./node_modules/markdown-it/lib/helpers/parse_link_destination.js ***! - \************************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Parse link destination\n//\n\n\n\nvar unescapeAll = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").unescapeAll;\n\n\nmodule.exports = function parseLinkDestination(str, pos, max) {\n var code, level,\n lines = 0,\n start = pos,\n result = {\n ok: false,\n pos: 0,\n lines: 0,\n str: ''\n };\n\n if (str.charCodeAt(pos) === 0x3C /* < */) {\n pos++;\n while (pos < max) {\n code = str.charCodeAt(pos);\n if (code === 0x0A /* \\n */) { return result; }\n if (code === 0x3C /* < */) { return result; }\n if (code === 0x3E /* > */) {\n result.pos = pos + 1;\n result.str = unescapeAll(str.slice(start + 1, pos));\n result.ok = true;\n return result;\n }\n if (code === 0x5C /* \\ */ && pos + 1 < max) {\n pos += 2;\n continue;\n }\n\n pos++;\n }\n\n // no closing '>'\n return result;\n }\n\n // this should be ... } else { ... branch\n\n level = 0;\n while (pos < max) {\n code = str.charCodeAt(pos);\n\n if (code === 0x20) { break; }\n\n // ascii control characters\n if (code < 0x20 || code === 0x7F) { break; }\n\n if (code === 0x5C /* \\ */ && pos + 1 < max) {\n if (str.charCodeAt(pos + 1) === 0x20) { break; }\n pos += 2;\n continue;\n }\n\n if (code === 0x28 /* ( */) {\n level++;\n if (level > 32) { return result; }\n }\n\n if (code === 0x29 /* ) */) {\n if (level === 0) { break; }\n level--;\n }\n\n pos++;\n }\n\n if (start === pos) { return result; }\n if (level !== 0) { return result; }\n\n result.str = unescapeAll(str.slice(start, pos));\n result.lines = lines;\n result.pos = pos;\n result.ok = true;\n return result;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/helpers/parse_link_destination.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/helpers/parse_link_label.js": -/*!******************************************************************!*\ - !*** ./node_modules/markdown-it/lib/helpers/parse_link_label.js ***! - \******************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Parse link label\n//\n// this function assumes that first character (\"[\") already matches;\n// returns the end of the label\n//\n\n\nmodule.exports = function parseLinkLabel(state, start, disableNested) {\n var level, found, marker, prevPos,\n labelEnd = -1,\n max = state.posMax,\n oldPos = state.pos;\n\n state.pos = start + 1;\n level = 1;\n\n while (state.pos < max) {\n marker = state.src.charCodeAt(state.pos);\n if (marker === 0x5D /* ] */) {\n level--;\n if (level === 0) {\n found = true;\n break;\n }\n }\n\n prevPos = state.pos;\n state.md.inline.skipToken(state);\n if (marker === 0x5B /* [ */) {\n if (prevPos === state.pos - 1) {\n // increase level if we find text `[`, which is not a part of any token\n level++;\n } else if (disableNested) {\n state.pos = oldPos;\n return -1;\n }\n }\n }\n\n if (found) {\n labelEnd = state.pos;\n }\n\n // restore old state\n state.pos = oldPos;\n\n return labelEnd;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/helpers/parse_link_label.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/helpers/parse_link_title.js": -/*!******************************************************************!*\ - !*** ./node_modules/markdown-it/lib/helpers/parse_link_title.js ***! - \******************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Parse link title\n//\n\n\n\nvar unescapeAll = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").unescapeAll;\n\n\nmodule.exports = function parseLinkTitle(str, pos, max) {\n var code,\n marker,\n lines = 0,\n start = pos,\n result = {\n ok: false,\n pos: 0,\n lines: 0,\n str: ''\n };\n\n if (pos >= max) { return result; }\n\n marker = str.charCodeAt(pos);\n\n if (marker !== 0x22 /* \" */ && marker !== 0x27 /* ' */ && marker !== 0x28 /* ( */) { return result; }\n\n pos++;\n\n // if opening marker is \"(\", switch it to closing marker \")\"\n if (marker === 0x28) { marker = 0x29; }\n\n while (pos < max) {\n code = str.charCodeAt(pos);\n if (code === marker) {\n result.pos = pos + 1;\n result.lines = lines;\n result.str = unescapeAll(str.slice(start + 1, pos));\n result.ok = true;\n return result;\n } else if (code === 0x28 /* ( */ && marker === 0x29 /* ) */) {\n return result;\n } else if (code === 0x0A) {\n lines++;\n } else if (code === 0x5C /* \\ */ && pos + 1 < max) {\n pos++;\n if (str.charCodeAt(pos) === 0x0A) {\n lines++;\n }\n }\n\n pos++;\n }\n\n return result;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/helpers/parse_link_title.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/index.js": -/*!***********************************************!*\ - !*** ./node_modules/markdown-it/lib/index.js ***! - \***********************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Main parser class\n\n\n\n\nvar utils = __webpack_require__(/*! ./common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\");\nvar helpers = __webpack_require__(/*! ./helpers */ \"./node_modules/markdown-it/lib/helpers/index.js\");\nvar Renderer = __webpack_require__(/*! ./renderer */ \"./node_modules/markdown-it/lib/renderer.js\");\nvar ParserCore = __webpack_require__(/*! ./parser_core */ \"./node_modules/markdown-it/lib/parser_core.js\");\nvar ParserBlock = __webpack_require__(/*! ./parser_block */ \"./node_modules/markdown-it/lib/parser_block.js\");\nvar ParserInline = __webpack_require__(/*! ./parser_inline */ \"./node_modules/markdown-it/lib/parser_inline.js\");\nvar LinkifyIt = __webpack_require__(/*! linkify-it */ \"./node_modules/linkify-it/index.js\");\nvar mdurl = __webpack_require__(/*! mdurl */ \"./node_modules/mdurl/index.js\");\nvar punycode = __webpack_require__(/*! punycode */ \"../../node_modules/punycode/punycode.js\");\n\n\nvar config = {\n default: __webpack_require__(/*! ./presets/default */ \"./node_modules/markdown-it/lib/presets/default.js\"),\n zero: __webpack_require__(/*! ./presets/zero */ \"./node_modules/markdown-it/lib/presets/zero.js\"),\n commonmark: __webpack_require__(/*! ./presets/commonmark */ \"./node_modules/markdown-it/lib/presets/commonmark.js\")\n};\n\n////////////////////////////////////////////////////////////////////////////////\n//\n// This validator can prohibit more than really needed to prevent XSS. It's a\n// tradeoff to keep code simple and to be secure by default.\n//\n// If you need different setup - override validator method as you wish. Or\n// replace it with dummy function and use external sanitizer.\n//\n\nvar BAD_PROTO_RE = /^(vbscript|javascript|file|data):/;\nvar GOOD_DATA_RE = /^data:image\\/(gif|png|jpeg|webp);/;\n\nfunction validateLink(url) {\n // url should be normalized at this point, and existing entities are decoded\n var str = url.trim().toLowerCase();\n\n return BAD_PROTO_RE.test(str) ? (GOOD_DATA_RE.test(str) ? true : false) : true;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\n\nvar RECODE_HOSTNAME_FOR = [ 'http:', 'https:', 'mailto:' ];\n\nfunction normalizeLink(url) {\n var parsed = mdurl.parse(url, true);\n\n if (parsed.hostname) {\n // Encode hostnames in urls like:\n // `http://host/`, `https://host/`, `mailto:user@host`, `//host/`\n //\n // We don't encode unknown schemas, because it's likely that we encode\n // something we shouldn't (e.g. `skype:name` treated as `skype:host`)\n //\n if (!parsed.protocol || RECODE_HOSTNAME_FOR.indexOf(parsed.protocol) >= 0) {\n try {\n parsed.hostname = punycode.toASCII(parsed.hostname);\n } catch (er) { /**/ }\n }\n }\n\n return mdurl.encode(mdurl.format(parsed));\n}\n\nfunction normalizeLinkText(url) {\n var parsed = mdurl.parse(url, true);\n\n if (parsed.hostname) {\n // Encode hostnames in urls like:\n // `http://host/`, `https://host/`, `mailto:user@host`, `//host/`\n //\n // We don't encode unknown schemas, because it's likely that we encode\n // something we shouldn't (e.g. `skype:name` treated as `skype:host`)\n //\n if (!parsed.protocol || RECODE_HOSTNAME_FOR.indexOf(parsed.protocol) >= 0) {\n try {\n parsed.hostname = punycode.toUnicode(parsed.hostname);\n } catch (er) { /**/ }\n }\n }\n\n // add '%' to exclude list because of https://github.com/markdown-it/markdown-it/issues/720\n return mdurl.decode(mdurl.format(parsed), mdurl.decode.defaultChars + '%');\n}\n\n\n/**\n * class MarkdownIt\n *\n * Main parser/renderer class.\n *\n * ##### Usage\n *\n * ```javascript\n * // node.js, \"classic\" way:\n * var MarkdownIt = require('markdown-it'),\n * md = new MarkdownIt();\n * var result = md.render('# markdown-it rulezz!');\n *\n * // node.js, the same, but with sugar:\n * var md = require('markdown-it')();\n * var result = md.render('# markdown-it rulezz!');\n *\n * // browser without AMD, added to \"window\" on script load\n * // Note, there are no dash.\n * var md = window.markdownit();\n * var result = md.render('# markdown-it rulezz!');\n * ```\n *\n * Single line rendering, without paragraph wrap:\n *\n * ```javascript\n * var md = require('markdown-it')();\n * var result = md.renderInline('__markdown-it__ rulezz!');\n * ```\n **/\n\n/**\n * new MarkdownIt([presetName, options])\n * - presetName (String): optional, `commonmark` / `zero`\n * - options (Object)\n *\n * Creates parser instanse with given config. Can be called without `new`.\n *\n * ##### presetName\n *\n * MarkdownIt provides named presets as a convenience to quickly\n * enable/disable active syntax rules and options for common use cases.\n *\n * - [\"commonmark\"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/commonmark.js) -\n * configures parser to strict [CommonMark](http://commonmark.org/) mode.\n * - [default](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/default.js) -\n * similar to GFM, used when no preset name given. Enables all available rules,\n * but still without html, typographer & autolinker.\n * - [\"zero\"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/zero.js) -\n * all rules disabled. Useful to quickly setup your config via `.enable()`.\n * For example, when you need only `bold` and `italic` markup and nothing else.\n *\n * ##### options:\n *\n * - __html__ - `false`. Set `true` to enable HTML tags in source. Be careful!\n * That's not safe! You may need external sanitizer to protect output from XSS.\n * It's better to extend features via plugins, instead of enabling HTML.\n * - __xhtmlOut__ - `false`. Set `true` to add '/' when closing single tags\n * (`
`). This is needed only for full CommonMark compatibility. In real\n * world you will need HTML output.\n * - __breaks__ - `false`. Set `true` to convert `\\n` in paragraphs into `
`.\n * - __langPrefix__ - `language-`. CSS language class prefix for fenced blocks.\n * Can be useful for external highlighters.\n * - __linkify__ - `false`. Set `true` to autoconvert URL-like text to links.\n * - __typographer__ - `false`. Set `true` to enable [some language-neutral\n * replacement](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/replacements.js) +\n * quotes beautification (smartquotes).\n * - __quotes__ - `“”‘’`, String or Array. Double + single quotes replacement\n * pairs, when typographer enabled and smartquotes on. For example, you can\n * use `'«»„“'` for Russian, `'„“‚‘'` for German, and\n * `['«\\xA0', '\\xA0»', '‹\\xA0', '\\xA0›']` for French (including nbsp).\n * - __highlight__ - `null`. Highlighter function for fenced code blocks.\n * Highlighter `function (str, lang)` should return escaped HTML. It can also\n * return empty string if the source was not changed and should be escaped\n * externaly. If result starts with `):\n *\n * ```javascript\n * var hljs = require('highlight.js') // https://highlightjs.org/\n *\n * // Actual default values\n * var md = require('markdown-it')({\n * highlight: function (str, lang) {\n * if (lang && hljs.getLanguage(lang)) {\n * try {\n * return '
' +\n *                hljs.highlight(lang, str, true).value +\n *                '
';\n * } catch (__) {}\n * }\n *\n * return '
' + md.utils.escapeHtml(str) + '
';\n * }\n * });\n * ```\n *\n **/\nfunction MarkdownIt(presetName, options) {\n if (!(this instanceof MarkdownIt)) {\n return new MarkdownIt(presetName, options);\n }\n\n if (!options) {\n if (!utils.isString(presetName)) {\n options = presetName || {};\n presetName = 'default';\n }\n }\n\n /**\n * MarkdownIt#inline -> ParserInline\n *\n * Instance of [[ParserInline]]. You may need it to add new rules when\n * writing plugins. For simple rules control use [[MarkdownIt.disable]] and\n * [[MarkdownIt.enable]].\n **/\n this.inline = new ParserInline();\n\n /**\n * MarkdownIt#block -> ParserBlock\n *\n * Instance of [[ParserBlock]]. You may need it to add new rules when\n * writing plugins. For simple rules control use [[MarkdownIt.disable]] and\n * [[MarkdownIt.enable]].\n **/\n this.block = new ParserBlock();\n\n /**\n * MarkdownIt#core -> Core\n *\n * Instance of [[Core]] chain executor. You may need it to add new rules when\n * writing plugins. For simple rules control use [[MarkdownIt.disable]] and\n * [[MarkdownIt.enable]].\n **/\n this.core = new ParserCore();\n\n /**\n * MarkdownIt#renderer -> Renderer\n *\n * Instance of [[Renderer]]. Use it to modify output look. Or to add rendering\n * rules for new token types, generated by plugins.\n *\n * ##### Example\n *\n * ```javascript\n * var md = require('markdown-it')();\n *\n * function myToken(tokens, idx, options, env, self) {\n * //...\n * return result;\n * };\n *\n * md.renderer.rules['my_token'] = myToken\n * ```\n *\n * See [[Renderer]] docs and [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.js).\n **/\n this.renderer = new Renderer();\n\n /**\n * MarkdownIt#linkify -> LinkifyIt\n *\n * [linkify-it](https://github.com/markdown-it/linkify-it) instance.\n * Used by [linkify](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/linkify.js)\n * rule.\n **/\n this.linkify = new LinkifyIt();\n\n /**\n * MarkdownIt#validateLink(url) -> Boolean\n *\n * Link validation function. CommonMark allows too much in links. By default\n * we disable `javascript:`, `vbscript:`, `file:` schemas, and almost all `data:...` schemas\n * except some embedded image types.\n *\n * You can change this behaviour:\n *\n * ```javascript\n * var md = require('markdown-it')();\n * // enable everything\n * md.validateLink = function () { return true; }\n * ```\n **/\n this.validateLink = validateLink;\n\n /**\n * MarkdownIt#normalizeLink(url) -> String\n *\n * Function used to encode link url to a machine-readable format,\n * which includes url-encoding, punycode, etc.\n **/\n this.normalizeLink = normalizeLink;\n\n /**\n * MarkdownIt#normalizeLinkText(url) -> String\n *\n * Function used to decode link url to a human-readable format`\n **/\n this.normalizeLinkText = normalizeLinkText;\n\n\n // Expose utils & helpers for easy acces from plugins\n\n /**\n * MarkdownIt#utils -> utils\n *\n * Assorted utility functions, useful to write plugins. See details\n * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/common/utils.js).\n **/\n this.utils = utils;\n\n /**\n * MarkdownIt#helpers -> helpers\n *\n * Link components parser functions, useful to write plugins. See details\n * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/helpers).\n **/\n this.helpers = utils.assign({}, helpers);\n\n\n this.options = {};\n this.configure(presetName);\n\n if (options) { this.set(options); }\n}\n\n\n/** chainable\n * MarkdownIt.set(options)\n *\n * Set parser options (in the same format as in constructor). Probably, you\n * will never need it, but you can change options after constructor call.\n *\n * ##### Example\n *\n * ```javascript\n * var md = require('markdown-it')()\n * .set({ html: true, breaks: true })\n * .set({ typographer, true });\n * ```\n *\n * __Note:__ To achieve the best possible performance, don't modify a\n * `markdown-it` instance options on the fly. If you need multiple configurations\n * it's best to create multiple instances and initialize each with separate\n * config.\n **/\nMarkdownIt.prototype.set = function (options) {\n utils.assign(this.options, options);\n return this;\n};\n\n\n/** chainable, internal\n * MarkdownIt.configure(presets)\n *\n * Batch load of all options and compenent settings. This is internal method,\n * and you probably will not need it. But if you will - see available presets\n * and data structure [here](https://github.com/markdown-it/markdown-it/tree/master/lib/presets)\n *\n * We strongly recommend to use presets instead of direct config loads. That\n * will give better compatibility with next versions.\n **/\nMarkdownIt.prototype.configure = function (presets) {\n var self = this, presetName;\n\n if (utils.isString(presets)) {\n presetName = presets;\n presets = config[presetName];\n if (!presets) { throw new Error('Wrong `markdown-it` preset \"' + presetName + '\", check name'); }\n }\n\n if (!presets) { throw new Error('Wrong `markdown-it` preset, can\\'t be empty'); }\n\n if (presets.options) { self.set(presets.options); }\n\n if (presets.components) {\n Object.keys(presets.components).forEach(function (name) {\n if (presets.components[name].rules) {\n self[name].ruler.enableOnly(presets.components[name].rules);\n }\n if (presets.components[name].rules2) {\n self[name].ruler2.enableOnly(presets.components[name].rules2);\n }\n });\n }\n return this;\n};\n\n\n/** chainable\n * MarkdownIt.enable(list, ignoreInvalid)\n * - list (String|Array): rule name or list of rule names to enable\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\n *\n * Enable list or rules. It will automatically find appropriate components,\n * containing rules with given names. If rule not found, and `ignoreInvalid`\n * not set - throws exception.\n *\n * ##### Example\n *\n * ```javascript\n * var md = require('markdown-it')()\n * .enable(['sub', 'sup'])\n * .disable('smartquotes');\n * ```\n **/\nMarkdownIt.prototype.enable = function (list, ignoreInvalid) {\n var result = [];\n\n if (!Array.isArray(list)) { list = [ list ]; }\n\n [ 'core', 'block', 'inline' ].forEach(function (chain) {\n result = result.concat(this[chain].ruler.enable(list, true));\n }, this);\n\n result = result.concat(this.inline.ruler2.enable(list, true));\n\n var missed = list.filter(function (name) { return result.indexOf(name) < 0; });\n\n if (missed.length && !ignoreInvalid) {\n throw new Error('MarkdownIt. Failed to enable unknown rule(s): ' + missed);\n }\n\n return this;\n};\n\n\n/** chainable\n * MarkdownIt.disable(list, ignoreInvalid)\n * - list (String|Array): rule name or list of rule names to disable.\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\n *\n * The same as [[MarkdownIt.enable]], but turn specified rules off.\n **/\nMarkdownIt.prototype.disable = function (list, ignoreInvalid) {\n var result = [];\n\n if (!Array.isArray(list)) { list = [ list ]; }\n\n [ 'core', 'block', 'inline' ].forEach(function (chain) {\n result = result.concat(this[chain].ruler.disable(list, true));\n }, this);\n\n result = result.concat(this.inline.ruler2.disable(list, true));\n\n var missed = list.filter(function (name) { return result.indexOf(name) < 0; });\n\n if (missed.length && !ignoreInvalid) {\n throw new Error('MarkdownIt. Failed to disable unknown rule(s): ' + missed);\n }\n return this;\n};\n\n\n/** chainable\n * MarkdownIt.use(plugin, params)\n *\n * Load specified plugin with given params into current parser instance.\n * It's just a sugar to call `plugin(md, params)` with curring.\n *\n * ##### Example\n *\n * ```javascript\n * var iterator = require('markdown-it-for-inline');\n * var md = require('markdown-it')()\n * .use(iterator, 'foo_replace', 'text', function (tokens, idx) {\n * tokens[idx].content = tokens[idx].content.replace(/foo/g, 'bar');\n * });\n * ```\n **/\nMarkdownIt.prototype.use = function (plugin /*, params, ... */) {\n var args = [ this ].concat(Array.prototype.slice.call(arguments, 1));\n plugin.apply(plugin, args);\n return this;\n};\n\n\n/** internal\n * MarkdownIt.parse(src, env) -> Array\n * - src (String): source string\n * - env (Object): environment sandbox\n *\n * Parse input string and return list of block tokens (special token type\n * \"inline\" will contain list of inline tokens). You should not call this\n * method directly, until you write custom renderer (for example, to produce\n * AST).\n *\n * `env` is used to pass data between \"distributed\" rules and return additional\n * metadata like reference info, needed for the renderer. It also can be used to\n * inject data in specific cases. Usually, you will be ok to pass `{}`,\n * and then pass updated object to renderer.\n **/\nMarkdownIt.prototype.parse = function (src, env) {\n if (typeof src !== 'string') {\n throw new Error('Input data should be a String');\n }\n\n var state = new this.core.State(src, this, env);\n\n this.core.process(state);\n\n return state.tokens;\n};\n\n\n/**\n * MarkdownIt.render(src [, env]) -> String\n * - src (String): source string\n * - env (Object): environment sandbox\n *\n * Render markdown string into html. It does all magic for you :).\n *\n * `env` can be used to inject additional metadata (`{}` by default).\n * But you will not need it with high probability. See also comment\n * in [[MarkdownIt.parse]].\n **/\nMarkdownIt.prototype.render = function (src, env) {\n env = env || {};\n\n return this.renderer.render(this.parse(src, env), this.options, env);\n};\n\n\n/** internal\n * MarkdownIt.parseInline(src, env) -> Array\n * - src (String): source string\n * - env (Object): environment sandbox\n *\n * The same as [[MarkdownIt.parse]] but skip all block rules. It returns the\n * block tokens list with the single `inline` element, containing parsed inline\n * tokens in `children` property. Also updates `env` object.\n **/\nMarkdownIt.prototype.parseInline = function (src, env) {\n var state = new this.core.State(src, this, env);\n\n state.inlineMode = true;\n this.core.process(state);\n\n return state.tokens;\n};\n\n\n/**\n * MarkdownIt.renderInline(src [, env]) -> String\n * - src (String): source string\n * - env (Object): environment sandbox\n *\n * Similar to [[MarkdownIt.render]] but for single paragraph content. Result\n * will NOT be wrapped into `

` tags.\n **/\nMarkdownIt.prototype.renderInline = function (src, env) {\n env = env || {};\n\n return this.renderer.render(this.parseInline(src, env), this.options, env);\n};\n\n\nmodule.exports = MarkdownIt;\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/index.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/parser_block.js": -/*!******************************************************!*\ - !*** ./node_modules/markdown-it/lib/parser_block.js ***! - \******************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("/** internal\n * class ParserBlock\n *\n * Block-level tokenizer.\n **/\n\n\n\nvar Ruler = __webpack_require__(/*! ./ruler */ \"./node_modules/markdown-it/lib/ruler.js\");\n\n\nvar _rules = [\n // First 2 params - rule name & source. Secondary array - list of rules,\n // which can be terminated by this one.\n [ 'table', __webpack_require__(/*! ./rules_block/table */ \"./node_modules/markdown-it/lib/rules_block/table.js\"), [ 'paragraph', 'reference' ] ],\n [ 'code', __webpack_require__(/*! ./rules_block/code */ \"./node_modules/markdown-it/lib/rules_block/code.js\") ],\n [ 'fence', __webpack_require__(/*! ./rules_block/fence */ \"./node_modules/markdown-it/lib/rules_block/fence.js\"), [ 'paragraph', 'reference', 'blockquote', 'list' ] ],\n [ 'blockquote', __webpack_require__(/*! ./rules_block/blockquote */ \"./node_modules/markdown-it/lib/rules_block/blockquote.js\"), [ 'paragraph', 'reference', 'blockquote', 'list' ] ],\n [ 'hr', __webpack_require__(/*! ./rules_block/hr */ \"./node_modules/markdown-it/lib/rules_block/hr.js\"), [ 'paragraph', 'reference', 'blockquote', 'list' ] ],\n [ 'list', __webpack_require__(/*! ./rules_block/list */ \"./node_modules/markdown-it/lib/rules_block/list.js\"), [ 'paragraph', 'reference', 'blockquote' ] ],\n [ 'reference', __webpack_require__(/*! ./rules_block/reference */ \"./node_modules/markdown-it/lib/rules_block/reference.js\") ],\n [ 'heading', __webpack_require__(/*! ./rules_block/heading */ \"./node_modules/markdown-it/lib/rules_block/heading.js\"), [ 'paragraph', 'reference', 'blockquote' ] ],\n [ 'lheading', __webpack_require__(/*! ./rules_block/lheading */ \"./node_modules/markdown-it/lib/rules_block/lheading.js\") ],\n [ 'html_block', __webpack_require__(/*! ./rules_block/html_block */ \"./node_modules/markdown-it/lib/rules_block/html_block.js\"), [ 'paragraph', 'reference', 'blockquote' ] ],\n [ 'paragraph', __webpack_require__(/*! ./rules_block/paragraph */ \"./node_modules/markdown-it/lib/rules_block/paragraph.js\") ]\n];\n\n\n/**\n * new ParserBlock()\n **/\nfunction ParserBlock() {\n /**\n * ParserBlock#ruler -> Ruler\n *\n * [[Ruler]] instance. Keep configuration of block rules.\n **/\n this.ruler = new Ruler();\n\n for (var i = 0; i < _rules.length; i++) {\n this.ruler.push(_rules[i][0], _rules[i][1], { alt: (_rules[i][2] || []).slice() });\n }\n}\n\n\n// Generate tokens for input range\n//\nParserBlock.prototype.tokenize = function (state, startLine, endLine) {\n var ok, i,\n rules = this.ruler.getRules(''),\n len = rules.length,\n line = startLine,\n hasEmptyLines = false,\n maxNesting = state.md.options.maxNesting;\n\n while (line < endLine) {\n state.line = line = state.skipEmptyLines(line);\n if (line >= endLine) { break; }\n\n // Termination condition for nested calls.\n // Nested calls currently used for blockquotes & lists\n if (state.sCount[line] < state.blkIndent) { break; }\n\n // If nesting level exceeded - skip tail to the end. That's not ordinary\n // situation and we should not care about content.\n if (state.level >= maxNesting) {\n state.line = endLine;\n break;\n }\n\n // Try all possible rules.\n // On success, rule should:\n //\n // - update `state.line`\n // - update `state.tokens`\n // - return true\n\n for (i = 0; i < len; i++) {\n ok = rules[i](state, line, endLine, false);\n if (ok) { break; }\n }\n\n // set state.tight if we had an empty line before current tag\n // i.e. latest empty line should not count\n state.tight = !hasEmptyLines;\n\n // paragraph might \"eat\" one newline after it in nested lists\n if (state.isEmpty(state.line - 1)) {\n hasEmptyLines = true;\n }\n\n line = state.line;\n\n if (line < endLine && state.isEmpty(line)) {\n hasEmptyLines = true;\n line++;\n state.line = line;\n }\n }\n};\n\n\n/**\n * ParserBlock.parse(str, md, env, outTokens)\n *\n * Process input string and push block tokens into `outTokens`\n **/\nParserBlock.prototype.parse = function (src, md, env, outTokens) {\n var state;\n\n if (!src) { return; }\n\n state = new this.State(src, md, env, outTokens);\n\n this.tokenize(state, state.line, state.lineMax);\n};\n\n\nParserBlock.prototype.State = __webpack_require__(/*! ./rules_block/state_block */ \"./node_modules/markdown-it/lib/rules_block/state_block.js\");\n\n\nmodule.exports = ParserBlock;\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/parser_block.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/parser_core.js": -/*!*****************************************************!*\ - !*** ./node_modules/markdown-it/lib/parser_core.js ***! - \*****************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("/** internal\n * class Core\n *\n * Top-level rules executor. Glues block/inline parsers and does intermediate\n * transformations.\n **/\n\n\n\nvar Ruler = __webpack_require__(/*! ./ruler */ \"./node_modules/markdown-it/lib/ruler.js\");\n\n\nvar _rules = [\n [ 'normalize', __webpack_require__(/*! ./rules_core/normalize */ \"./node_modules/markdown-it/lib/rules_core/normalize.js\") ],\n [ 'block', __webpack_require__(/*! ./rules_core/block */ \"./node_modules/markdown-it/lib/rules_core/block.js\") ],\n [ 'inline', __webpack_require__(/*! ./rules_core/inline */ \"./node_modules/markdown-it/lib/rules_core/inline.js\") ],\n [ 'linkify', __webpack_require__(/*! ./rules_core/linkify */ \"./node_modules/markdown-it/lib/rules_core/linkify.js\") ],\n [ 'replacements', __webpack_require__(/*! ./rules_core/replacements */ \"./node_modules/markdown-it/lib/rules_core/replacements.js\") ],\n [ 'smartquotes', __webpack_require__(/*! ./rules_core/smartquotes */ \"./node_modules/markdown-it/lib/rules_core/smartquotes.js\") ]\n];\n\n\n/**\n * new Core()\n **/\nfunction Core() {\n /**\n * Core#ruler -> Ruler\n *\n * [[Ruler]] instance. Keep configuration of core rules.\n **/\n this.ruler = new Ruler();\n\n for (var i = 0; i < _rules.length; i++) {\n this.ruler.push(_rules[i][0], _rules[i][1]);\n }\n}\n\n\n/**\n * Core.process(state)\n *\n * Executes core chain rules.\n **/\nCore.prototype.process = function (state) {\n var i, l, rules;\n\n rules = this.ruler.getRules('');\n\n for (i = 0, l = rules.length; i < l; i++) {\n rules[i](state);\n }\n};\n\nCore.prototype.State = __webpack_require__(/*! ./rules_core/state_core */ \"./node_modules/markdown-it/lib/rules_core/state_core.js\");\n\n\nmodule.exports = Core;\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/parser_core.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/parser_inline.js": -/*!*******************************************************!*\ - !*** ./node_modules/markdown-it/lib/parser_inline.js ***! - \*******************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("/** internal\n * class ParserInline\n *\n * Tokenizes paragraph content.\n **/\n\n\n\nvar Ruler = __webpack_require__(/*! ./ruler */ \"./node_modules/markdown-it/lib/ruler.js\");\n\n\n////////////////////////////////////////////////////////////////////////////////\n// Parser rules\n\nvar _rules = [\n [ 'text', __webpack_require__(/*! ./rules_inline/text */ \"./node_modules/markdown-it/lib/rules_inline/text.js\") ],\n [ 'newline', __webpack_require__(/*! ./rules_inline/newline */ \"./node_modules/markdown-it/lib/rules_inline/newline.js\") ],\n [ 'escape', __webpack_require__(/*! ./rules_inline/escape */ \"./node_modules/markdown-it/lib/rules_inline/escape.js\") ],\n [ 'backticks', __webpack_require__(/*! ./rules_inline/backticks */ \"./node_modules/markdown-it/lib/rules_inline/backticks.js\") ],\n [ 'strikethrough', __webpack_require__(/*! ./rules_inline/strikethrough */ \"./node_modules/markdown-it/lib/rules_inline/strikethrough.js\").tokenize ],\n [ 'emphasis', __webpack_require__(/*! ./rules_inline/emphasis */ \"./node_modules/markdown-it/lib/rules_inline/emphasis.js\").tokenize ],\n [ 'link', __webpack_require__(/*! ./rules_inline/link */ \"./node_modules/markdown-it/lib/rules_inline/link.js\") ],\n [ 'image', __webpack_require__(/*! ./rules_inline/image */ \"./node_modules/markdown-it/lib/rules_inline/image.js\") ],\n [ 'autolink', __webpack_require__(/*! ./rules_inline/autolink */ \"./node_modules/markdown-it/lib/rules_inline/autolink.js\") ],\n [ 'html_inline', __webpack_require__(/*! ./rules_inline/html_inline */ \"./node_modules/markdown-it/lib/rules_inline/html_inline.js\") ],\n [ 'entity', __webpack_require__(/*! ./rules_inline/entity */ \"./node_modules/markdown-it/lib/rules_inline/entity.js\") ]\n];\n\nvar _rules2 = [\n [ 'balance_pairs', __webpack_require__(/*! ./rules_inline/balance_pairs */ \"./node_modules/markdown-it/lib/rules_inline/balance_pairs.js\") ],\n [ 'strikethrough', __webpack_require__(/*! ./rules_inline/strikethrough */ \"./node_modules/markdown-it/lib/rules_inline/strikethrough.js\").postProcess ],\n [ 'emphasis', __webpack_require__(/*! ./rules_inline/emphasis */ \"./node_modules/markdown-it/lib/rules_inline/emphasis.js\").postProcess ],\n [ 'text_collapse', __webpack_require__(/*! ./rules_inline/text_collapse */ \"./node_modules/markdown-it/lib/rules_inline/text_collapse.js\") ]\n];\n\n\n/**\n * new ParserInline()\n **/\nfunction ParserInline() {\n var i;\n\n /**\n * ParserInline#ruler -> Ruler\n *\n * [[Ruler]] instance. Keep configuration of inline rules.\n **/\n this.ruler = new Ruler();\n\n for (i = 0; i < _rules.length; i++) {\n this.ruler.push(_rules[i][0], _rules[i][1]);\n }\n\n /**\n * ParserInline#ruler2 -> Ruler\n *\n * [[Ruler]] instance. Second ruler used for post-processing\n * (e.g. in emphasis-like rules).\n **/\n this.ruler2 = new Ruler();\n\n for (i = 0; i < _rules2.length; i++) {\n this.ruler2.push(_rules2[i][0], _rules2[i][1]);\n }\n}\n\n\n// Skip single token by running all rules in validation mode;\n// returns `true` if any rule reported success\n//\nParserInline.prototype.skipToken = function (state) {\n var ok, i, pos = state.pos,\n rules = this.ruler.getRules(''),\n len = rules.length,\n maxNesting = state.md.options.maxNesting,\n cache = state.cache;\n\n\n if (typeof cache[pos] !== 'undefined') {\n state.pos = cache[pos];\n return;\n }\n\n if (state.level < maxNesting) {\n for (i = 0; i < len; i++) {\n // Increment state.level and decrement it later to limit recursion.\n // It's harmless to do here, because no tokens are created. But ideally,\n // we'd need a separate private state variable for this purpose.\n //\n state.level++;\n ok = rules[i](state, true);\n state.level--;\n\n if (ok) { break; }\n }\n } else {\n // Too much nesting, just skip until the end of the paragraph.\n //\n // NOTE: this will cause links to behave incorrectly in the following case,\n // when an amount of `[` is exactly equal to `maxNesting + 1`:\n //\n // [[[[[[[[[[[[[[[[[[[[[foo]()\n //\n // TODO: remove this workaround when CM standard will allow nested links\n // (we can replace it by preventing links from being parsed in\n // validation mode)\n //\n state.pos = state.posMax;\n }\n\n if (!ok) { state.pos++; }\n cache[pos] = state.pos;\n};\n\n\n// Generate tokens for input range\n//\nParserInline.prototype.tokenize = function (state) {\n var ok, i,\n rules = this.ruler.getRules(''),\n len = rules.length,\n end = state.posMax,\n maxNesting = state.md.options.maxNesting;\n\n while (state.pos < end) {\n // Try all possible rules.\n // On success, rule should:\n //\n // - update `state.pos`\n // - update `state.tokens`\n // - return true\n\n if (state.level < maxNesting) {\n for (i = 0; i < len; i++) {\n ok = rules[i](state, false);\n if (ok) { break; }\n }\n }\n\n if (ok) {\n if (state.pos >= end) { break; }\n continue;\n }\n\n state.pending += state.src[state.pos++];\n }\n\n if (state.pending) {\n state.pushPending();\n }\n};\n\n\n/**\n * ParserInline.parse(str, md, env, outTokens)\n *\n * Process input string and push inline tokens into `outTokens`\n **/\nParserInline.prototype.parse = function (str, md, env, outTokens) {\n var i, rules, len;\n var state = new this.State(str, md, env, outTokens);\n\n this.tokenize(state);\n\n rules = this.ruler2.getRules('');\n len = rules.length;\n\n for (i = 0; i < len; i++) {\n rules[i](state);\n }\n};\n\n\nParserInline.prototype.State = __webpack_require__(/*! ./rules_inline/state_inline */ \"./node_modules/markdown-it/lib/rules_inline/state_inline.js\");\n\n\nmodule.exports = ParserInline;\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/parser_inline.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/presets/commonmark.js": -/*!************************************************************!*\ - !*** ./node_modules/markdown-it/lib/presets/commonmark.js ***! - \************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Commonmark default options\n\n\n\n\nmodule.exports = {\n options: {\n html: true, // Enable HTML tags in source\n xhtmlOut: true, // Use '/' to close single tags (
)\n breaks: false, // Convert '\\n' in paragraphs into
\n langPrefix: 'language-', // CSS language prefix for fenced blocks\n linkify: false, // autoconvert URL-like texts to links\n\n // Enable some language-neutral replacements + quotes beautification\n typographer: false,\n\n // Double + single quotes replacement pairs, when typographer enabled,\n // and smartquotes on. Could be either a String or an Array.\n //\n // For example, you can use '«»„“' for Russian, '„“‚‘' for German,\n // and ['«\\xA0', '\\xA0»', '‹\\xA0', '\\xA0›'] for French (including nbsp).\n quotes: '\\u201c\\u201d\\u2018\\u2019', /* “”‘’ */\n\n // Highlighter function. Should return escaped HTML,\n // or '' if the source string is not changed and should be escaped externaly.\n // If result starts with )\n breaks: false, // Convert '\\n' in paragraphs into
\n langPrefix: 'language-', // CSS language prefix for fenced blocks\n linkify: false, // autoconvert URL-like texts to links\n\n // Enable some language-neutral replacements + quotes beautification\n typographer: false,\n\n // Double + single quotes replacement pairs, when typographer enabled,\n // and smartquotes on. Could be either a String or an Array.\n //\n // For example, you can use '«»„“' for Russian, '„“‚‘' for German,\n // and ['«\\xA0', '\\xA0»', '‹\\xA0', '\\xA0›'] for French (including nbsp).\n quotes: '\\u201c\\u201d\\u2018\\u2019', /* “”‘’ */\n\n // Highlighter function. Should return escaped HTML,\n // or '' if the source string is not changed and should be escaped externaly.\n // If result starts with )\n breaks: false, // Convert '\\n' in paragraphs into
\n langPrefix: 'language-', // CSS language prefix for fenced blocks\n linkify: false, // autoconvert URL-like texts to links\n\n // Enable some language-neutral replacements + quotes beautification\n typographer: false,\n\n // Double + single quotes replacement pairs, when typographer enabled,\n // and smartquotes on. Could be either a String or an Array.\n //\n // For example, you can use '«»„“' for Russian, '„“‚‘' for German,\n // and ['«\\xA0', '\\xA0»', '‹\\xA0', '\\xA0›'] for French (including nbsp).\n quotes: '\\u201c\\u201d\\u2018\\u2019', /* “”‘’ */\n\n // Highlighter function. Should return escaped HTML,\n // or '' if the source string is not changed and should be escaped externaly.\n // If result starts with ' +\n escapeHtml(tokens[idx].content) +\n '';\n};\n\n\ndefault_rules.code_block = function (tokens, idx, options, env, slf) {\n var token = tokens[idx];\n\n return '' +\n escapeHtml(tokens[idx].content) +\n '\\n';\n};\n\n\ndefault_rules.fence = function (tokens, idx, options, env, slf) {\n var token = tokens[idx],\n info = token.info ? unescapeAll(token.info).trim() : '',\n langName = '',\n langAttrs = '',\n highlighted, i, arr, tmpAttrs, tmpToken;\n\n if (info) {\n arr = info.split(/(\\s+)/g);\n langName = arr[0];\n langAttrs = arr.slice(2).join('');\n }\n\n if (options.highlight) {\n highlighted = options.highlight(token.content, langName, langAttrs) || escapeHtml(token.content);\n } else {\n highlighted = escapeHtml(token.content);\n }\n\n if (highlighted.indexOf(''\n + highlighted\n + '\\n';\n }\n\n\n return '

'\n        + highlighted\n        + '
\\n';\n};\n\n\ndefault_rules.image = function (tokens, idx, options, env, slf) {\n var token = tokens[idx];\n\n // \"alt\" attr MUST be set, even if empty. Because it's mandatory and\n // should be placed on proper position for tests.\n //\n // Replace content with actual value\n\n token.attrs[token.attrIndex('alt')][1] =\n slf.renderInlineAsText(token.children, options, env);\n\n return slf.renderToken(tokens, idx, options);\n};\n\n\ndefault_rules.hardbreak = function (tokens, idx, options /*, env */) {\n return options.xhtmlOut ? '
\\n' : '
\\n';\n};\ndefault_rules.softbreak = function (tokens, idx, options /*, env */) {\n return options.breaks ? (options.xhtmlOut ? '
\\n' : '
\\n') : '\\n';\n};\n\n\ndefault_rules.text = function (tokens, idx /*, options, env */) {\n return escapeHtml(tokens[idx].content);\n};\n\n\ndefault_rules.html_block = function (tokens, idx /*, options, env */) {\n return tokens[idx].content;\n};\ndefault_rules.html_inline = function (tokens, idx /*, options, env */) {\n return tokens[idx].content;\n};\n\n\n/**\n * new Renderer()\n *\n * Creates new [[Renderer]] instance and fill [[Renderer#rules]] with defaults.\n **/\nfunction Renderer() {\n\n /**\n * Renderer#rules -> Object\n *\n * Contains render rules for tokens. Can be updated and extended.\n *\n * ##### Example\n *\n * ```javascript\n * var md = require('markdown-it')();\n *\n * md.renderer.rules.strong_open = function () { return ''; };\n * md.renderer.rules.strong_close = function () { return ''; };\n *\n * var result = md.renderInline(...);\n * ```\n *\n * Each rule is called as independent static function with fixed signature:\n *\n * ```javascript\n * function my_token_render(tokens, idx, options, env, renderer) {\n * // ...\n * return renderedHTML;\n * }\n * ```\n *\n * See [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.js)\n * for more details and examples.\n **/\n this.rules = assign({}, default_rules);\n}\n\n\n/**\n * Renderer.renderAttrs(token) -> String\n *\n * Render token attributes to string.\n **/\nRenderer.prototype.renderAttrs = function renderAttrs(token) {\n var i, l, result;\n\n if (!token.attrs) { return ''; }\n\n result = '';\n\n for (i = 0, l = token.attrs.length; i < l; i++) {\n result += ' ' + escapeHtml(token.attrs[i][0]) + '=\"' + escapeHtml(token.attrs[i][1]) + '\"';\n }\n\n return result;\n};\n\n\n/**\n * Renderer.renderToken(tokens, idx, options) -> String\n * - tokens (Array): list of tokens\n * - idx (Numbed): token index to render\n * - options (Object): params of parser instance\n *\n * Default token renderer. Can be overriden by custom function\n * in [[Renderer#rules]].\n **/\nRenderer.prototype.renderToken = function renderToken(tokens, idx, options) {\n var nextToken,\n result = '',\n needLf = false,\n token = tokens[idx];\n\n // Tight list paragraphs\n if (token.hidden) {\n return '';\n }\n\n // Insert a newline between hidden paragraph and subsequent opening\n // block-level tag.\n //\n // For example, here we should insert a newline before blockquote:\n // - a\n // >\n //\n if (token.block && token.nesting !== -1 && idx && tokens[idx - 1].hidden) {\n result += '\\n';\n }\n\n // Add token name, e.g. ``.\n //\n needLf = false;\n }\n }\n }\n }\n\n result += needLf ? '>\\n' : '>';\n\n return result;\n};\n\n\n/**\n * Renderer.renderInline(tokens, options, env) -> String\n * - tokens (Array): list on block tokens to renter\n * - options (Object): params of parser instance\n * - env (Object): additional data from parsed input (references, for example)\n *\n * The same as [[Renderer.render]], but for single token of `inline` type.\n **/\nRenderer.prototype.renderInline = function (tokens, options, env) {\n var type,\n result = '',\n rules = this.rules;\n\n for (var i = 0, len = tokens.length; i < len; i++) {\n type = tokens[i].type;\n\n if (typeof rules[type] !== 'undefined') {\n result += rules[type](tokens, i, options, env, this);\n } else {\n result += this.renderToken(tokens, i, options);\n }\n }\n\n return result;\n};\n\n\n/** internal\n * Renderer.renderInlineAsText(tokens, options, env) -> String\n * - tokens (Array): list on block tokens to renter\n * - options (Object): params of parser instance\n * - env (Object): additional data from parsed input (references, for example)\n *\n * Special kludge for image `alt` attributes to conform CommonMark spec.\n * Don't try to use it! Spec requires to show `alt` content with stripped markup,\n * instead of simple escaping.\n **/\nRenderer.prototype.renderInlineAsText = function (tokens, options, env) {\n var result = '';\n\n for (var i = 0, len = tokens.length; i < len; i++) {\n if (tokens[i].type === 'text') {\n result += tokens[i].content;\n } else if (tokens[i].type === 'image') {\n result += this.renderInlineAsText(tokens[i].children, options, env);\n }\n }\n\n return result;\n};\n\n\n/**\n * Renderer.render(tokens, options, env) -> String\n * - tokens (Array): list on block tokens to renter\n * - options (Object): params of parser instance\n * - env (Object): additional data from parsed input (references, for example)\n *\n * Takes token stream and generates HTML. Probably, you will never need to call\n * this method directly.\n **/\nRenderer.prototype.render = function (tokens, options, env) {\n var i, len, type,\n result = '',\n rules = this.rules;\n\n for (i = 0, len = tokens.length; i < len; i++) {\n type = tokens[i].type;\n\n if (type === 'inline') {\n result += this.renderInline(tokens[i].children, options, env);\n } else if (typeof rules[type] !== 'undefined') {\n result += rules[tokens[i].type](tokens, i, options, env, this);\n } else {\n result += this.renderToken(tokens, i, options, env);\n }\n }\n\n return result;\n};\n\nmodule.exports = Renderer;\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/renderer.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/ruler.js": -/*!***********************************************!*\ - !*** ./node_modules/markdown-it/lib/ruler.js ***! - \***********************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("/**\n * class Ruler\n *\n * Helper class, used by [[MarkdownIt#core]], [[MarkdownIt#block]] and\n * [[MarkdownIt#inline]] to manage sequences of functions (rules):\n *\n * - keep rules in defined order\n * - assign the name to each rule\n * - enable/disable rules\n * - add/replace rules\n * - allow assign rules to additional named chains (in the same)\n * - cacheing lists of active rules\n *\n * You will not need use this class directly until write plugins. For simple\n * rules control use [[MarkdownIt.disable]], [[MarkdownIt.enable]] and\n * [[MarkdownIt.use]].\n **/\n\n\n\n/**\n * new Ruler()\n **/\nfunction Ruler() {\n // List of added rules. Each element is:\n //\n // {\n // name: XXX,\n // enabled: Boolean,\n // fn: Function(),\n // alt: [ name2, name3 ]\n // }\n //\n this.__rules__ = [];\n\n // Cached rule chains.\n //\n // First level - chain name, '' for default.\n // Second level - diginal anchor for fast filtering by charcodes.\n //\n this.__cache__ = null;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Helper methods, should not be used directly\n\n\n// Find rule index by name\n//\nRuler.prototype.__find__ = function (name) {\n for (var i = 0; i < this.__rules__.length; i++) {\n if (this.__rules__[i].name === name) {\n return i;\n }\n }\n return -1;\n};\n\n\n// Build rules lookup cache\n//\nRuler.prototype.__compile__ = function () {\n var self = this;\n var chains = [ '' ];\n\n // collect unique names\n self.__rules__.forEach(function (rule) {\n if (!rule.enabled) { return; }\n\n rule.alt.forEach(function (altName) {\n if (chains.indexOf(altName) < 0) {\n chains.push(altName);\n }\n });\n });\n\n self.__cache__ = {};\n\n chains.forEach(function (chain) {\n self.__cache__[chain] = [];\n self.__rules__.forEach(function (rule) {\n if (!rule.enabled) { return; }\n\n if (chain && rule.alt.indexOf(chain) < 0) { return; }\n\n self.__cache__[chain].push(rule.fn);\n });\n });\n};\n\n\n/**\n * Ruler.at(name, fn [, options])\n * - name (String): rule name to replace.\n * - fn (Function): new rule function.\n * - options (Object): new rule options (not mandatory).\n *\n * Replace rule by name with new function & options. Throws error if name not\n * found.\n *\n * ##### Options:\n *\n * - __alt__ - array with names of \"alternate\" chains.\n *\n * ##### Example\n *\n * Replace existing typographer replacement rule with new one:\n *\n * ```javascript\n * var md = require('markdown-it')();\n *\n * md.core.ruler.at('replacements', function replace(state) {\n * //...\n * });\n * ```\n **/\nRuler.prototype.at = function (name, fn, options) {\n var index = this.__find__(name);\n var opt = options || {};\n\n if (index === -1) { throw new Error('Parser rule not found: ' + name); }\n\n this.__rules__[index].fn = fn;\n this.__rules__[index].alt = opt.alt || [];\n this.__cache__ = null;\n};\n\n\n/**\n * Ruler.before(beforeName, ruleName, fn [, options])\n * - beforeName (String): new rule will be added before this one.\n * - ruleName (String): name of added rule.\n * - fn (Function): rule function.\n * - options (Object): rule options (not mandatory).\n *\n * Add new rule to chain before one with given name. See also\n * [[Ruler.after]], [[Ruler.push]].\n *\n * ##### Options:\n *\n * - __alt__ - array with names of \"alternate\" chains.\n *\n * ##### Example\n *\n * ```javascript\n * var md = require('markdown-it')();\n *\n * md.block.ruler.before('paragraph', 'my_rule', function replace(state) {\n * //...\n * });\n * ```\n **/\nRuler.prototype.before = function (beforeName, ruleName, fn, options) {\n var index = this.__find__(beforeName);\n var opt = options || {};\n\n if (index === -1) { throw new Error('Parser rule not found: ' + beforeName); }\n\n this.__rules__.splice(index, 0, {\n name: ruleName,\n enabled: true,\n fn: fn,\n alt: opt.alt || []\n });\n\n this.__cache__ = null;\n};\n\n\n/**\n * Ruler.after(afterName, ruleName, fn [, options])\n * - afterName (String): new rule will be added after this one.\n * - ruleName (String): name of added rule.\n * - fn (Function): rule function.\n * - options (Object): rule options (not mandatory).\n *\n * Add new rule to chain after one with given name. See also\n * [[Ruler.before]], [[Ruler.push]].\n *\n * ##### Options:\n *\n * - __alt__ - array with names of \"alternate\" chains.\n *\n * ##### Example\n *\n * ```javascript\n * var md = require('markdown-it')();\n *\n * md.inline.ruler.after('text', 'my_rule', function replace(state) {\n * //...\n * });\n * ```\n **/\nRuler.prototype.after = function (afterName, ruleName, fn, options) {\n var index = this.__find__(afterName);\n var opt = options || {};\n\n if (index === -1) { throw new Error('Parser rule not found: ' + afterName); }\n\n this.__rules__.splice(index + 1, 0, {\n name: ruleName,\n enabled: true,\n fn: fn,\n alt: opt.alt || []\n });\n\n this.__cache__ = null;\n};\n\n/**\n * Ruler.push(ruleName, fn [, options])\n * - ruleName (String): name of added rule.\n * - fn (Function): rule function.\n * - options (Object): rule options (not mandatory).\n *\n * Push new rule to the end of chain. See also\n * [[Ruler.before]], [[Ruler.after]].\n *\n * ##### Options:\n *\n * - __alt__ - array with names of \"alternate\" chains.\n *\n * ##### Example\n *\n * ```javascript\n * var md = require('markdown-it')();\n *\n * md.core.ruler.push('my_rule', function replace(state) {\n * //...\n * });\n * ```\n **/\nRuler.prototype.push = function (ruleName, fn, options) {\n var opt = options || {};\n\n this.__rules__.push({\n name: ruleName,\n enabled: true,\n fn: fn,\n alt: opt.alt || []\n });\n\n this.__cache__ = null;\n};\n\n\n/**\n * Ruler.enable(list [, ignoreInvalid]) -> Array\n * - list (String|Array): list of rule names to enable.\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\n *\n * Enable rules with given names. If any rule name not found - throw Error.\n * Errors can be disabled by second param.\n *\n * Returns list of found rule names (if no exception happened).\n *\n * See also [[Ruler.disable]], [[Ruler.enableOnly]].\n **/\nRuler.prototype.enable = function (list, ignoreInvalid) {\n if (!Array.isArray(list)) { list = [ list ]; }\n\n var result = [];\n\n // Search by name and enable\n list.forEach(function (name) {\n var idx = this.__find__(name);\n\n if (idx < 0) {\n if (ignoreInvalid) { return; }\n throw new Error('Rules manager: invalid rule name ' + name);\n }\n this.__rules__[idx].enabled = true;\n result.push(name);\n }, this);\n\n this.__cache__ = null;\n return result;\n};\n\n\n/**\n * Ruler.enableOnly(list [, ignoreInvalid])\n * - list (String|Array): list of rule names to enable (whitelist).\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\n *\n * Enable rules with given names, and disable everything else. If any rule name\n * not found - throw Error. Errors can be disabled by second param.\n *\n * See also [[Ruler.disable]], [[Ruler.enable]].\n **/\nRuler.prototype.enableOnly = function (list, ignoreInvalid) {\n if (!Array.isArray(list)) { list = [ list ]; }\n\n this.__rules__.forEach(function (rule) { rule.enabled = false; });\n\n this.enable(list, ignoreInvalid);\n};\n\n\n/**\n * Ruler.disable(list [, ignoreInvalid]) -> Array\n * - list (String|Array): list of rule names to disable.\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\n *\n * Disable rules with given names. If any rule name not found - throw Error.\n * Errors can be disabled by second param.\n *\n * Returns list of found rule names (if no exception happened).\n *\n * See also [[Ruler.enable]], [[Ruler.enableOnly]].\n **/\nRuler.prototype.disable = function (list, ignoreInvalid) {\n if (!Array.isArray(list)) { list = [ list ]; }\n\n var result = [];\n\n // Search by name and disable\n list.forEach(function (name) {\n var idx = this.__find__(name);\n\n if (idx < 0) {\n if (ignoreInvalid) { return; }\n throw new Error('Rules manager: invalid rule name ' + name);\n }\n this.__rules__[idx].enabled = false;\n result.push(name);\n }, this);\n\n this.__cache__ = null;\n return result;\n};\n\n\n/**\n * Ruler.getRules(chainName) -> Array\n *\n * Return array of active functions (rules) for given chain name. It analyzes\n * rules configuration, compiles caches if not exists and returns result.\n *\n * Default chain name is `''` (empty string). It can't be skipped. That's\n * done intentionally, to keep signature monomorphic for high speed.\n **/\nRuler.prototype.getRules = function (chainName) {\n if (this.__cache__ === null) {\n this.__compile__();\n }\n\n // Chain can be empty, if rules disabled. But we still have to return Array.\n return this.__cache__[chainName] || [];\n};\n\nmodule.exports = Ruler;\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/ruler.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_block/blockquote.js": -/*!****************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_block/blockquote.js ***! - \****************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Block quotes\n\n\n\nvar isSpace = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").isSpace;\n\n\nmodule.exports = function blockquote(state, startLine, endLine, silent) {\n var adjustTab,\n ch,\n i,\n initial,\n l,\n lastLineEmpty,\n lines,\n nextLine,\n offset,\n oldBMarks,\n oldBSCount,\n oldIndent,\n oldParentType,\n oldSCount,\n oldTShift,\n spaceAfterMarker,\n terminate,\n terminatorRules,\n token,\n isOutdented,\n oldLineMax = state.lineMax,\n pos = state.bMarks[startLine] + state.tShift[startLine],\n max = state.eMarks[startLine];\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }\n\n // check the block quote marker\n if (state.src.charCodeAt(pos++) !== 0x3E/* > */) { return false; }\n\n // we know that it's going to be a valid blockquote,\n // so no point trying to find the end of it in silent mode\n if (silent) { return true; }\n\n // set offset past spaces and \">\"\n initial = offset = state.sCount[startLine] + 1;\n\n // skip one optional space after '>'\n if (state.src.charCodeAt(pos) === 0x20 /* space */) {\n // ' > test '\n // ^ -- position start of line here:\n pos++;\n initial++;\n offset++;\n adjustTab = false;\n spaceAfterMarker = true;\n } else if (state.src.charCodeAt(pos) === 0x09 /* tab */) {\n spaceAfterMarker = true;\n\n if ((state.bsCount[startLine] + offset) % 4 === 3) {\n // ' >\\t test '\n // ^ -- position start of line here (tab has width===1)\n pos++;\n initial++;\n offset++;\n adjustTab = false;\n } else {\n // ' >\\t test '\n // ^ -- position start of line here + shift bsCount slightly\n // to make extra space appear\n adjustTab = true;\n }\n } else {\n spaceAfterMarker = false;\n }\n\n oldBMarks = [ state.bMarks[startLine] ];\n state.bMarks[startLine] = pos;\n\n while (pos < max) {\n ch = state.src.charCodeAt(pos);\n\n if (isSpace(ch)) {\n if (ch === 0x09) {\n offset += 4 - (offset + state.bsCount[startLine] + (adjustTab ? 1 : 0)) % 4;\n } else {\n offset++;\n }\n } else {\n break;\n }\n\n pos++;\n }\n\n oldBSCount = [ state.bsCount[startLine] ];\n state.bsCount[startLine] = state.sCount[startLine] + 1 + (spaceAfterMarker ? 1 : 0);\n\n lastLineEmpty = pos >= max;\n\n oldSCount = [ state.sCount[startLine] ];\n state.sCount[startLine] = offset - initial;\n\n oldTShift = [ state.tShift[startLine] ];\n state.tShift[startLine] = pos - state.bMarks[startLine];\n\n terminatorRules = state.md.block.ruler.getRules('blockquote');\n\n oldParentType = state.parentType;\n state.parentType = 'blockquote';\n\n // Search the end of the block\n //\n // Block ends with either:\n // 1. an empty line outside:\n // ```\n // > test\n //\n // ```\n // 2. an empty line inside:\n // ```\n // >\n // test\n // ```\n // 3. another tag:\n // ```\n // > test\n // - - -\n // ```\n for (nextLine = startLine + 1; nextLine < endLine; nextLine++) {\n // check if it's outdented, i.e. it's inside list item and indented\n // less than said list item:\n //\n // ```\n // 1. anything\n // > current blockquote\n // 2. checking this line\n // ```\n isOutdented = state.sCount[nextLine] < state.blkIndent;\n\n pos = state.bMarks[nextLine] + state.tShift[nextLine];\n max = state.eMarks[nextLine];\n\n if (pos >= max) {\n // Case 1: line is not inside the blockquote, and this line is empty.\n break;\n }\n\n if (state.src.charCodeAt(pos++) === 0x3E/* > */ && !isOutdented) {\n // This line is inside the blockquote.\n\n // set offset past spaces and \">\"\n initial = offset = state.sCount[nextLine] + 1;\n\n // skip one optional space after '>'\n if (state.src.charCodeAt(pos) === 0x20 /* space */) {\n // ' > test '\n // ^ -- position start of line here:\n pos++;\n initial++;\n offset++;\n adjustTab = false;\n spaceAfterMarker = true;\n } else if (state.src.charCodeAt(pos) === 0x09 /* tab */) {\n spaceAfterMarker = true;\n\n if ((state.bsCount[nextLine] + offset) % 4 === 3) {\n // ' >\\t test '\n // ^ -- position start of line here (tab has width===1)\n pos++;\n initial++;\n offset++;\n adjustTab = false;\n } else {\n // ' >\\t test '\n // ^ -- position start of line here + shift bsCount slightly\n // to make extra space appear\n adjustTab = true;\n }\n } else {\n spaceAfterMarker = false;\n }\n\n oldBMarks.push(state.bMarks[nextLine]);\n state.bMarks[nextLine] = pos;\n\n while (pos < max) {\n ch = state.src.charCodeAt(pos);\n\n if (isSpace(ch)) {\n if (ch === 0x09) {\n offset += 4 - (offset + state.bsCount[nextLine] + (adjustTab ? 1 : 0)) % 4;\n } else {\n offset++;\n }\n } else {\n break;\n }\n\n pos++;\n }\n\n lastLineEmpty = pos >= max;\n\n oldBSCount.push(state.bsCount[nextLine]);\n state.bsCount[nextLine] = state.sCount[nextLine] + 1 + (spaceAfterMarker ? 1 : 0);\n\n oldSCount.push(state.sCount[nextLine]);\n state.sCount[nextLine] = offset - initial;\n\n oldTShift.push(state.tShift[nextLine]);\n state.tShift[nextLine] = pos - state.bMarks[nextLine];\n continue;\n }\n\n // Case 2: line is not inside the blockquote, and the last line was empty.\n if (lastLineEmpty) { break; }\n\n // Case 3: another tag found.\n terminate = false;\n for (i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n\n if (terminate) {\n // Quirk to enforce \"hard termination mode\" for paragraphs;\n // normally if you call `tokenize(state, startLine, nextLine)`,\n // paragraphs will look below nextLine for paragraph continuation,\n // but if blockquote is terminated by another tag, they shouldn't\n state.lineMax = nextLine;\n\n if (state.blkIndent !== 0) {\n // state.blkIndent was non-zero, we now set it to zero,\n // so we need to re-calculate all offsets to appear as\n // if indent wasn't changed\n oldBMarks.push(state.bMarks[nextLine]);\n oldBSCount.push(state.bsCount[nextLine]);\n oldTShift.push(state.tShift[nextLine]);\n oldSCount.push(state.sCount[nextLine]);\n state.sCount[nextLine] -= state.blkIndent;\n }\n\n break;\n }\n\n oldBMarks.push(state.bMarks[nextLine]);\n oldBSCount.push(state.bsCount[nextLine]);\n oldTShift.push(state.tShift[nextLine]);\n oldSCount.push(state.sCount[nextLine]);\n\n // A negative indentation means that this is a paragraph continuation\n //\n state.sCount[nextLine] = -1;\n }\n\n oldIndent = state.blkIndent;\n state.blkIndent = 0;\n\n token = state.push('blockquote_open', 'blockquote', 1);\n token.markup = '>';\n token.map = lines = [ startLine, 0 ];\n\n state.md.block.tokenize(state, startLine, nextLine);\n\n token = state.push('blockquote_close', 'blockquote', -1);\n token.markup = '>';\n\n state.lineMax = oldLineMax;\n state.parentType = oldParentType;\n lines[1] = state.line;\n\n // Restore original tShift; this might not be necessary since the parser\n // has already been here, but just to make sure we can do that.\n for (i = 0; i < oldTShift.length; i++) {\n state.bMarks[i + startLine] = oldBMarks[i];\n state.tShift[i + startLine] = oldTShift[i];\n state.sCount[i + startLine] = oldSCount[i];\n state.bsCount[i + startLine] = oldBSCount[i];\n }\n state.blkIndent = oldIndent;\n\n return true;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_block/blockquote.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_block/code.js": -/*!**********************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_block/code.js ***! - \**********************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Code block (4 spaces padded)\n\n\n\n\nmodule.exports = function code(state, startLine, endLine/*, silent*/) {\n var nextLine, last, token;\n\n if (state.sCount[startLine] - state.blkIndent < 4) { return false; }\n\n last = nextLine = startLine + 1;\n\n while (nextLine < endLine) {\n if (state.isEmpty(nextLine)) {\n nextLine++;\n continue;\n }\n\n if (state.sCount[nextLine] - state.blkIndent >= 4) {\n nextLine++;\n last = nextLine;\n continue;\n }\n break;\n }\n\n state.line = last;\n\n token = state.push('code_block', 'code', 0);\n token.content = state.getLines(startLine, last, 4 + state.blkIndent, true);\n token.map = [ startLine, state.line ];\n\n return true;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_block/code.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_block/fence.js": -/*!***********************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_block/fence.js ***! - \***********************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// fences (``` lang, ~~~ lang)\n\n\n\n\nmodule.exports = function fence(state, startLine, endLine, silent) {\n var marker, len, params, nextLine, mem, token, markup,\n haveEndMarker = false,\n pos = state.bMarks[startLine] + state.tShift[startLine],\n max = state.eMarks[startLine];\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }\n\n if (pos + 3 > max) { return false; }\n\n marker = state.src.charCodeAt(pos);\n\n if (marker !== 0x7E/* ~ */ && marker !== 0x60 /* ` */) {\n return false;\n }\n\n // scan marker length\n mem = pos;\n pos = state.skipChars(pos, marker);\n\n len = pos - mem;\n\n if (len < 3) { return false; }\n\n markup = state.src.slice(mem, pos);\n params = state.src.slice(pos, max);\n\n if (marker === 0x60 /* ` */) {\n if (params.indexOf(String.fromCharCode(marker)) >= 0) {\n return false;\n }\n }\n\n // Since start is found, we can report success here in validation mode\n if (silent) { return true; }\n\n // search end of block\n nextLine = startLine;\n\n for (;;) {\n nextLine++;\n if (nextLine >= endLine) {\n // unclosed block should be autoclosed by end of document.\n // also block seems to be autoclosed by end of parent\n break;\n }\n\n pos = mem = state.bMarks[nextLine] + state.tShift[nextLine];\n max = state.eMarks[nextLine];\n\n if (pos < max && state.sCount[nextLine] < state.blkIndent) {\n // non-empty line with negative indent should stop the list:\n // - ```\n // test\n break;\n }\n\n if (state.src.charCodeAt(pos) !== marker) { continue; }\n\n if (state.sCount[nextLine] - state.blkIndent >= 4) {\n // closing fence should be indented less than 4 spaces\n continue;\n }\n\n pos = state.skipChars(pos, marker);\n\n // closing code fence must be at least as long as the opening one\n if (pos - mem < len) { continue; }\n\n // make sure tail has spaces only\n pos = state.skipSpaces(pos);\n\n if (pos < max) { continue; }\n\n haveEndMarker = true;\n // found!\n break;\n }\n\n // If a fence has heading spaces, they should be removed from its inner block\n len = state.sCount[startLine];\n\n state.line = nextLine + (haveEndMarker ? 1 : 0);\n\n token = state.push('fence', 'code', 0);\n token.info = params;\n token.content = state.getLines(startLine + 1, nextLine, len, true);\n token.markup = markup;\n token.map = [ startLine, state.line ];\n\n return true;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_block/fence.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_block/heading.js": -/*!*************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_block/heading.js ***! - \*************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// heading (#, ##, ...)\n\n\n\nvar isSpace = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").isSpace;\n\n\nmodule.exports = function heading(state, startLine, endLine, silent) {\n var ch, level, tmp, token,\n pos = state.bMarks[startLine] + state.tShift[startLine],\n max = state.eMarks[startLine];\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }\n\n ch = state.src.charCodeAt(pos);\n\n if (ch !== 0x23/* # */ || pos >= max) { return false; }\n\n // count heading level\n level = 1;\n ch = state.src.charCodeAt(++pos);\n while (ch === 0x23/* # */ && pos < max && level <= 6) {\n level++;\n ch = state.src.charCodeAt(++pos);\n }\n\n if (level > 6 || (pos < max && !isSpace(ch))) { return false; }\n\n if (silent) { return true; }\n\n // Let's cut tails like ' ### ' from the end of string\n\n max = state.skipSpacesBack(max, pos);\n tmp = state.skipCharsBack(max, 0x23, pos); // #\n if (tmp > pos && isSpace(state.src.charCodeAt(tmp - 1))) {\n max = tmp;\n }\n\n state.line = startLine + 1;\n\n token = state.push('heading_open', 'h' + String(level), 1);\n token.markup = '########'.slice(0, level);\n token.map = [ startLine, state.line ];\n\n token = state.push('inline', '', 0);\n token.content = state.src.slice(pos, max).trim();\n token.map = [ startLine, state.line ];\n token.children = [];\n\n token = state.push('heading_close', 'h' + String(level), -1);\n token.markup = '########'.slice(0, level);\n\n return true;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_block/heading.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_block/hr.js": -/*!********************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_block/hr.js ***! - \********************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Horizontal rule\n\n\n\nvar isSpace = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").isSpace;\n\n\nmodule.exports = function hr(state, startLine, endLine, silent) {\n var marker, cnt, ch, token,\n pos = state.bMarks[startLine] + state.tShift[startLine],\n max = state.eMarks[startLine];\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }\n\n marker = state.src.charCodeAt(pos++);\n\n // Check hr marker\n if (marker !== 0x2A/* * */ &&\n marker !== 0x2D/* - */ &&\n marker !== 0x5F/* _ */) {\n return false;\n }\n\n // markers can be mixed with spaces, but there should be at least 3 of them\n\n cnt = 1;\n while (pos < max) {\n ch = state.src.charCodeAt(pos++);\n if (ch !== marker && !isSpace(ch)) { return false; }\n if (ch === marker) { cnt++; }\n }\n\n if (cnt < 3) { return false; }\n\n if (silent) { return true; }\n\n state.line = startLine + 1;\n\n token = state.push('hr', 'hr', 0);\n token.map = [ startLine, state.line ];\n token.markup = Array(cnt + 1).join(String.fromCharCode(marker));\n\n return true;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_block/hr.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_block/html_block.js": -/*!****************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_block/html_block.js ***! - \****************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// HTML block\n\n\n\n\nvar block_names = __webpack_require__(/*! ../common/html_blocks */ \"./node_modules/markdown-it/lib/common/html_blocks.js\");\nvar HTML_OPEN_CLOSE_TAG_RE = __webpack_require__(/*! ../common/html_re */ \"./node_modules/markdown-it/lib/common/html_re.js\").HTML_OPEN_CLOSE_TAG_RE;\n\n// An array of opening and corresponding closing sequences for html tags,\n// last argument defines whether it can terminate a paragraph or not\n//\nvar HTML_SEQUENCES = [\n [ /^<(script|pre|style)(?=(\\s|>|$))/i, /<\\/(script|pre|style)>/i, true ],\n [ /^/, true ],\n [ /^<\\?/, /\\?>/, true ],\n [ /^/, true ],\n [ /^/, true ],\n [ new RegExp('^|$))', 'i'), /^$/, true ],\n [ new RegExp(HTML_OPEN_CLOSE_TAG_RE.source + '\\\\s*$'), /^$/, false ]\n];\n\n\nmodule.exports = function html_block(state, startLine, endLine, silent) {\n var i, nextLine, token, lineText,\n pos = state.bMarks[startLine] + state.tShift[startLine],\n max = state.eMarks[startLine];\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }\n\n if (!state.md.options.html) { return false; }\n\n if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false; }\n\n lineText = state.src.slice(pos, max);\n\n for (i = 0; i < HTML_SEQUENCES.length; i++) {\n if (HTML_SEQUENCES[i][0].test(lineText)) { break; }\n }\n\n if (i === HTML_SEQUENCES.length) { return false; }\n\n if (silent) {\n // true if this sequence can be a terminator, false otherwise\n return HTML_SEQUENCES[i][2];\n }\n\n nextLine = startLine + 1;\n\n // If we are here - we detected HTML block.\n // Let's roll down till block end.\n if (!HTML_SEQUENCES[i][1].test(lineText)) {\n for (; nextLine < endLine; nextLine++) {\n if (state.sCount[nextLine] < state.blkIndent) { break; }\n\n pos = state.bMarks[nextLine] + state.tShift[nextLine];\n max = state.eMarks[nextLine];\n lineText = state.src.slice(pos, max);\n\n if (HTML_SEQUENCES[i][1].test(lineText)) {\n if (lineText.length !== 0) { nextLine++; }\n break;\n }\n }\n }\n\n state.line = nextLine;\n\n token = state.push('html_block', '', 0);\n token.map = [ startLine, nextLine ];\n token.content = state.getLines(startLine, nextLine, state.blkIndent, true);\n\n return true;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_block/html_block.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_block/lheading.js": -/*!**************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_block/lheading.js ***! - \**************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// lheading (---, ===)\n\n\n\n\nmodule.exports = function lheading(state, startLine, endLine/*, silent*/) {\n var content, terminate, i, l, token, pos, max, level, marker,\n nextLine = startLine + 1, oldParentType,\n terminatorRules = state.md.block.ruler.getRules('paragraph');\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }\n\n oldParentType = state.parentType;\n state.parentType = 'paragraph'; // use paragraph to match terminatorRules\n\n // jump line-by-line until empty one or EOF\n for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {\n // this would be a code block normally, but after paragraph\n // it's considered a lazy continuation regardless of what's there\n if (state.sCount[nextLine] - state.blkIndent > 3) { continue; }\n\n //\n // Check for underline in setext header\n //\n if (state.sCount[nextLine] >= state.blkIndent) {\n pos = state.bMarks[nextLine] + state.tShift[nextLine];\n max = state.eMarks[nextLine];\n\n if (pos < max) {\n marker = state.src.charCodeAt(pos);\n\n if (marker === 0x2D/* - */ || marker === 0x3D/* = */) {\n pos = state.skipChars(pos, marker);\n pos = state.skipSpaces(pos);\n\n if (pos >= max) {\n level = (marker === 0x3D/* = */ ? 1 : 2);\n break;\n }\n }\n }\n }\n\n // quirk for blockquotes, this line should already be checked by that rule\n if (state.sCount[nextLine] < 0) { continue; }\n\n // Some tags can terminate paragraph without empty line.\n terminate = false;\n for (i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n if (terminate) { break; }\n }\n\n if (!level) {\n // Didn't find valid underline\n return false;\n }\n\n content = state.getLines(startLine, nextLine, state.blkIndent, false).trim();\n\n state.line = nextLine + 1;\n\n token = state.push('heading_open', 'h' + String(level), 1);\n token.markup = String.fromCharCode(marker);\n token.map = [ startLine, state.line ];\n\n token = state.push('inline', '', 0);\n token.content = content;\n token.map = [ startLine, state.line - 1 ];\n token.children = [];\n\n token = state.push('heading_close', 'h' + String(level), -1);\n token.markup = String.fromCharCode(marker);\n\n state.parentType = oldParentType;\n\n return true;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_block/lheading.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_block/list.js": -/*!**********************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_block/list.js ***! - \**********************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Lists\n\n\n\nvar isSpace = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").isSpace;\n\n\n// Search `[-+*][\\n ]`, returns next pos after marker on success\n// or -1 on fail.\nfunction skipBulletListMarker(state, startLine) {\n var marker, pos, max, ch;\n\n pos = state.bMarks[startLine] + state.tShift[startLine];\n max = state.eMarks[startLine];\n\n marker = state.src.charCodeAt(pos++);\n // Check bullet\n if (marker !== 0x2A/* * */ &&\n marker !== 0x2D/* - */ &&\n marker !== 0x2B/* + */) {\n return -1;\n }\n\n if (pos < max) {\n ch = state.src.charCodeAt(pos);\n\n if (!isSpace(ch)) {\n // \" -test \" - is not a list item\n return -1;\n }\n }\n\n return pos;\n}\n\n// Search `\\d+[.)][\\n ]`, returns next pos after marker on success\n// or -1 on fail.\nfunction skipOrderedListMarker(state, startLine) {\n var ch,\n start = state.bMarks[startLine] + state.tShift[startLine],\n pos = start,\n max = state.eMarks[startLine];\n\n // List marker should have at least 2 chars (digit + dot)\n if (pos + 1 >= max) { return -1; }\n\n ch = state.src.charCodeAt(pos++);\n\n if (ch < 0x30/* 0 */ || ch > 0x39/* 9 */) { return -1; }\n\n for (;;) {\n // EOL -> fail\n if (pos >= max) { return -1; }\n\n ch = state.src.charCodeAt(pos++);\n\n if (ch >= 0x30/* 0 */ && ch <= 0x39/* 9 */) {\n\n // List marker should have no more than 9 digits\n // (prevents integer overflow in browsers)\n if (pos - start >= 10) { return -1; }\n\n continue;\n }\n\n // found valid marker\n if (ch === 0x29/* ) */ || ch === 0x2e/* . */) {\n break;\n }\n\n return -1;\n }\n\n\n if (pos < max) {\n ch = state.src.charCodeAt(pos);\n\n if (!isSpace(ch)) {\n // \" 1.test \" - is not a list item\n return -1;\n }\n }\n return pos;\n}\n\nfunction markTightParagraphs(state, idx) {\n var i, l,\n level = state.level + 2;\n\n for (i = idx + 2, l = state.tokens.length - 2; i < l; i++) {\n if (state.tokens[i].level === level && state.tokens[i].type === 'paragraph_open') {\n state.tokens[i + 2].hidden = true;\n state.tokens[i].hidden = true;\n i += 2;\n }\n }\n}\n\n\nmodule.exports = function list(state, startLine, endLine, silent) {\n var ch,\n contentStart,\n i,\n indent,\n indentAfterMarker,\n initial,\n isOrdered,\n itemLines,\n l,\n listLines,\n listTokIdx,\n markerCharCode,\n markerValue,\n max,\n nextLine,\n offset,\n oldListIndent,\n oldParentType,\n oldSCount,\n oldTShift,\n oldTight,\n pos,\n posAfterMarker,\n prevEmptyEnd,\n start,\n terminate,\n terminatorRules,\n token,\n isTerminatingParagraph = false,\n tight = true;\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }\n\n // Special case:\n // - item 1\n // - item 2\n // - item 3\n // - item 4\n // - this one is a paragraph continuation\n if (state.listIndent >= 0 &&\n state.sCount[startLine] - state.listIndent >= 4 &&\n state.sCount[startLine] < state.blkIndent) {\n return false;\n }\n\n // limit conditions when list can interrupt\n // a paragraph (validation mode only)\n if (silent && state.parentType === 'paragraph') {\n // Next list item should still terminate previous list item;\n //\n // This code can fail if plugins use blkIndent as well as lists,\n // but I hope the spec gets fixed long before that happens.\n //\n if (state.tShift[startLine] >= state.blkIndent) {\n isTerminatingParagraph = true;\n }\n }\n\n // Detect list type and position after marker\n if ((posAfterMarker = skipOrderedListMarker(state, startLine)) >= 0) {\n isOrdered = true;\n start = state.bMarks[startLine] + state.tShift[startLine];\n markerValue = Number(state.src.substr(start, posAfterMarker - start - 1));\n\n // If we're starting a new ordered list right after\n // a paragraph, it should start with 1.\n if (isTerminatingParagraph && markerValue !== 1) return false;\n\n } else if ((posAfterMarker = skipBulletListMarker(state, startLine)) >= 0) {\n isOrdered = false;\n\n } else {\n return false;\n }\n\n // If we're starting a new unordered list right after\n // a paragraph, first line should not be empty.\n if (isTerminatingParagraph) {\n if (state.skipSpaces(posAfterMarker) >= state.eMarks[startLine]) return false;\n }\n\n // We should terminate list on style change. Remember first one to compare.\n markerCharCode = state.src.charCodeAt(posAfterMarker - 1);\n\n // For validation mode we can terminate immediately\n if (silent) { return true; }\n\n // Start list\n listTokIdx = state.tokens.length;\n\n if (isOrdered) {\n token = state.push('ordered_list_open', 'ol', 1);\n if (markerValue !== 1) {\n token.attrs = [ [ 'start', markerValue ] ];\n }\n\n } else {\n token = state.push('bullet_list_open', 'ul', 1);\n }\n\n token.map = listLines = [ startLine, 0 ];\n token.markup = String.fromCharCode(markerCharCode);\n\n //\n // Iterate list items\n //\n\n nextLine = startLine;\n prevEmptyEnd = false;\n terminatorRules = state.md.block.ruler.getRules('list');\n\n oldParentType = state.parentType;\n state.parentType = 'list';\n\n while (nextLine < endLine) {\n pos = posAfterMarker;\n max = state.eMarks[nextLine];\n\n initial = offset = state.sCount[nextLine] + posAfterMarker - (state.bMarks[startLine] + state.tShift[startLine]);\n\n while (pos < max) {\n ch = state.src.charCodeAt(pos);\n\n if (ch === 0x09) {\n offset += 4 - (offset + state.bsCount[nextLine]) % 4;\n } else if (ch === 0x20) {\n offset++;\n } else {\n break;\n }\n\n pos++;\n }\n\n contentStart = pos;\n\n if (contentStart >= max) {\n // trimming space in \"- \\n 3\" case, indent is 1 here\n indentAfterMarker = 1;\n } else {\n indentAfterMarker = offset - initial;\n }\n\n // If we have more than 4 spaces, the indent is 1\n // (the rest is just indented code block)\n if (indentAfterMarker > 4) { indentAfterMarker = 1; }\n\n // \" - test\"\n // ^^^^^ - calculating total length of this thing\n indent = initial + indentAfterMarker;\n\n // Run subparser & write tokens\n token = state.push('list_item_open', 'li', 1);\n token.markup = String.fromCharCode(markerCharCode);\n token.map = itemLines = [ startLine, 0 ];\n\n // change current state, then restore it after parser subcall\n oldTight = state.tight;\n oldTShift = state.tShift[startLine];\n oldSCount = state.sCount[startLine];\n\n // - example list\n // ^ listIndent position will be here\n // ^ blkIndent position will be here\n //\n oldListIndent = state.listIndent;\n state.listIndent = state.blkIndent;\n state.blkIndent = indent;\n\n state.tight = true;\n state.tShift[startLine] = contentStart - state.bMarks[startLine];\n state.sCount[startLine] = offset;\n\n if (contentStart >= max && state.isEmpty(startLine + 1)) {\n // workaround for this case\n // (list item is empty, list terminates before \"foo\"):\n // ~~~~~~~~\n // -\n //\n // foo\n // ~~~~~~~~\n state.line = Math.min(state.line + 2, endLine);\n } else {\n state.md.block.tokenize(state, startLine, endLine, true);\n }\n\n // If any of list item is tight, mark list as tight\n if (!state.tight || prevEmptyEnd) {\n tight = false;\n }\n // Item become loose if finish with empty line,\n // but we should filter last element, because it means list finish\n prevEmptyEnd = (state.line - startLine) > 1 && state.isEmpty(state.line - 1);\n\n state.blkIndent = state.listIndent;\n state.listIndent = oldListIndent;\n state.tShift[startLine] = oldTShift;\n state.sCount[startLine] = oldSCount;\n state.tight = oldTight;\n\n token = state.push('list_item_close', 'li', -1);\n token.markup = String.fromCharCode(markerCharCode);\n\n nextLine = startLine = state.line;\n itemLines[1] = nextLine;\n contentStart = state.bMarks[startLine];\n\n if (nextLine >= endLine) { break; }\n\n //\n // Try to check if list is terminated or continued.\n //\n if (state.sCount[nextLine] < state.blkIndent) { break; }\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[startLine] - state.blkIndent >= 4) { break; }\n\n // fail if terminating block found\n terminate = false;\n for (i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n if (terminate) { break; }\n\n // fail if list has another type\n if (isOrdered) {\n posAfterMarker = skipOrderedListMarker(state, nextLine);\n if (posAfterMarker < 0) { break; }\n } else {\n posAfterMarker = skipBulletListMarker(state, nextLine);\n if (posAfterMarker < 0) { break; }\n }\n\n if (markerCharCode !== state.src.charCodeAt(posAfterMarker - 1)) { break; }\n }\n\n // Finalize list\n if (isOrdered) {\n token = state.push('ordered_list_close', 'ol', -1);\n } else {\n token = state.push('bullet_list_close', 'ul', -1);\n }\n token.markup = String.fromCharCode(markerCharCode);\n\n listLines[1] = nextLine;\n state.line = nextLine;\n\n state.parentType = oldParentType;\n\n // mark paragraphs tight if needed\n if (tight) {\n markTightParagraphs(state, listTokIdx);\n }\n\n return true;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_block/list.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_block/paragraph.js": -/*!***************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_block/paragraph.js ***! - \***************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Paragraph\n\n\n\n\nmodule.exports = function paragraph(state, startLine/*, endLine*/) {\n var content, terminate, i, l, token, oldParentType,\n nextLine = startLine + 1,\n terminatorRules = state.md.block.ruler.getRules('paragraph'),\n endLine = state.lineMax;\n\n oldParentType = state.parentType;\n state.parentType = 'paragraph';\n\n // jump line-by-line until empty one or EOF\n for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {\n // this would be a code block normally, but after paragraph\n // it's considered a lazy continuation regardless of what's there\n if (state.sCount[nextLine] - state.blkIndent > 3) { continue; }\n\n // quirk for blockquotes, this line should already be checked by that rule\n if (state.sCount[nextLine] < 0) { continue; }\n\n // Some tags can terminate paragraph without empty line.\n terminate = false;\n for (i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n if (terminate) { break; }\n }\n\n content = state.getLines(startLine, nextLine, state.blkIndent, false).trim();\n\n state.line = nextLine;\n\n token = state.push('paragraph_open', 'p', 1);\n token.map = [ startLine, state.line ];\n\n token = state.push('inline', '', 0);\n token.content = content;\n token.map = [ startLine, state.line ];\n token.children = [];\n\n token = state.push('paragraph_close', 'p', -1);\n\n state.parentType = oldParentType;\n\n return true;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_block/paragraph.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_block/reference.js": -/*!***************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_block/reference.js ***! - \***************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("\n\n\nvar normalizeReference = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").normalizeReference;\nvar isSpace = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").isSpace;\n\n\nmodule.exports = function reference(state, startLine, _endLine, silent) {\n var ch,\n destEndPos,\n destEndLineNo,\n endLine,\n href,\n i,\n l,\n label,\n labelEnd,\n oldParentType,\n res,\n start,\n str,\n terminate,\n terminatorRules,\n title,\n lines = 0,\n pos = state.bMarks[startLine] + state.tShift[startLine],\n max = state.eMarks[startLine],\n nextLine = startLine + 1;\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }\n\n if (state.src.charCodeAt(pos) !== 0x5B/* [ */) { return false; }\n\n // Simple check to quickly interrupt scan on [link](url) at the start of line.\n // Can be useful on practice: https://github.com/markdown-it/markdown-it/issues/54\n while (++pos < max) {\n if (state.src.charCodeAt(pos) === 0x5D /* ] */ &&\n state.src.charCodeAt(pos - 1) !== 0x5C/* \\ */) {\n if (pos + 1 === max) { return false; }\n if (state.src.charCodeAt(pos + 1) !== 0x3A/* : */) { return false; }\n break;\n }\n }\n\n endLine = state.lineMax;\n\n // jump line-by-line until empty one or EOF\n terminatorRules = state.md.block.ruler.getRules('reference');\n\n oldParentType = state.parentType;\n state.parentType = 'reference';\n\n for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {\n // this would be a code block normally, but after paragraph\n // it's considered a lazy continuation regardless of what's there\n if (state.sCount[nextLine] - state.blkIndent > 3) { continue; }\n\n // quirk for blockquotes, this line should already be checked by that rule\n if (state.sCount[nextLine] < 0) { continue; }\n\n // Some tags can terminate paragraph without empty line.\n terminate = false;\n for (i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n if (terminate) { break; }\n }\n\n str = state.getLines(startLine, nextLine, state.blkIndent, false).trim();\n max = str.length;\n\n for (pos = 1; pos < max; pos++) {\n ch = str.charCodeAt(pos);\n if (ch === 0x5B /* [ */) {\n return false;\n } else if (ch === 0x5D /* ] */) {\n labelEnd = pos;\n break;\n } else if (ch === 0x0A /* \\n */) {\n lines++;\n } else if (ch === 0x5C /* \\ */) {\n pos++;\n if (pos < max && str.charCodeAt(pos) === 0x0A) {\n lines++;\n }\n }\n }\n\n if (labelEnd < 0 || str.charCodeAt(labelEnd + 1) !== 0x3A/* : */) { return false; }\n\n // [label]: destination 'title'\n // ^^^ skip optional whitespace here\n for (pos = labelEnd + 2; pos < max; pos++) {\n ch = str.charCodeAt(pos);\n if (ch === 0x0A) {\n lines++;\n } else if (isSpace(ch)) {\n /*eslint no-empty:0*/\n } else {\n break;\n }\n }\n\n // [label]: destination 'title'\n // ^^^^^^^^^^^ parse this\n res = state.md.helpers.parseLinkDestination(str, pos, max);\n if (!res.ok) { return false; }\n\n href = state.md.normalizeLink(res.str);\n if (!state.md.validateLink(href)) { return false; }\n\n pos = res.pos;\n lines += res.lines;\n\n // save cursor state, we could require to rollback later\n destEndPos = pos;\n destEndLineNo = lines;\n\n // [label]: destination 'title'\n // ^^^ skipping those spaces\n start = pos;\n for (; pos < max; pos++) {\n ch = str.charCodeAt(pos);\n if (ch === 0x0A) {\n lines++;\n } else if (isSpace(ch)) {\n /*eslint no-empty:0*/\n } else {\n break;\n }\n }\n\n // [label]: destination 'title'\n // ^^^^^^^ parse this\n res = state.md.helpers.parseLinkTitle(str, pos, max);\n if (pos < max && start !== pos && res.ok) {\n title = res.str;\n pos = res.pos;\n lines += res.lines;\n } else {\n title = '';\n pos = destEndPos;\n lines = destEndLineNo;\n }\n\n // skip trailing spaces until the rest of the line\n while (pos < max) {\n ch = str.charCodeAt(pos);\n if (!isSpace(ch)) { break; }\n pos++;\n }\n\n if (pos < max && str.charCodeAt(pos) !== 0x0A) {\n if (title) {\n // garbage at the end of the line after title,\n // but it could still be a valid reference if we roll back\n title = '';\n pos = destEndPos;\n lines = destEndLineNo;\n while (pos < max) {\n ch = str.charCodeAt(pos);\n if (!isSpace(ch)) { break; }\n pos++;\n }\n }\n }\n\n if (pos < max && str.charCodeAt(pos) !== 0x0A) {\n // garbage at the end of the line\n return false;\n }\n\n label = normalizeReference(str.slice(1, labelEnd));\n if (!label) {\n // CommonMark 0.20 disallows empty labels\n return false;\n }\n\n // Reference can not terminate anything. This check is for safety only.\n /*istanbul ignore if*/\n if (silent) { return true; }\n\n if (typeof state.env.references === 'undefined') {\n state.env.references = {};\n }\n if (typeof state.env.references[label] === 'undefined') {\n state.env.references[label] = { title: title, href: href };\n }\n\n state.parentType = oldParentType;\n\n state.line = startLine + lines + 1;\n return true;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_block/reference.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_block/state_block.js": -/*!*****************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_block/state_block.js ***! - \*****************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Parser state class\n\n\n\nvar Token = __webpack_require__(/*! ../token */ \"./node_modules/markdown-it/lib/token.js\");\nvar isSpace = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").isSpace;\n\n\nfunction StateBlock(src, md, env, tokens) {\n var ch, s, start, pos, len, indent, offset, indent_found;\n\n this.src = src;\n\n // link to parser instance\n this.md = md;\n\n this.env = env;\n\n //\n // Internal state vartiables\n //\n\n this.tokens = tokens;\n\n this.bMarks = []; // line begin offsets for fast jumps\n this.eMarks = []; // line end offsets for fast jumps\n this.tShift = []; // offsets of the first non-space characters (tabs not expanded)\n this.sCount = []; // indents for each line (tabs expanded)\n\n // An amount of virtual spaces (tabs expanded) between beginning\n // of each line (bMarks) and real beginning of that line.\n //\n // It exists only as a hack because blockquotes override bMarks\n // losing information in the process.\n //\n // It's used only when expanding tabs, you can think about it as\n // an initial tab length, e.g. bsCount=21 applied to string `\\t123`\n // means first tab should be expanded to 4-21%4 === 3 spaces.\n //\n this.bsCount = [];\n\n // block parser variables\n this.blkIndent = 0; // required block content indent (for example, if we are\n // inside a list, it would be positioned after list marker)\n this.line = 0; // line index in src\n this.lineMax = 0; // lines count\n this.tight = false; // loose/tight mode for lists\n this.ddIndent = -1; // indent of the current dd block (-1 if there isn't any)\n this.listIndent = -1; // indent of the current list block (-1 if there isn't any)\n\n // can be 'blockquote', 'list', 'root', 'paragraph' or 'reference'\n // used in lists to determine if they interrupt a paragraph\n this.parentType = 'root';\n\n this.level = 0;\n\n // renderer\n this.result = '';\n\n // Create caches\n // Generate markers.\n s = this.src;\n indent_found = false;\n\n for (start = pos = indent = offset = 0, len = s.length; pos < len; pos++) {\n ch = s.charCodeAt(pos);\n\n if (!indent_found) {\n if (isSpace(ch)) {\n indent++;\n\n if (ch === 0x09) {\n offset += 4 - offset % 4;\n } else {\n offset++;\n }\n continue;\n } else {\n indent_found = true;\n }\n }\n\n if (ch === 0x0A || pos === len - 1) {\n if (ch !== 0x0A) { pos++; }\n this.bMarks.push(start);\n this.eMarks.push(pos);\n this.tShift.push(indent);\n this.sCount.push(offset);\n this.bsCount.push(0);\n\n indent_found = false;\n indent = 0;\n offset = 0;\n start = pos + 1;\n }\n }\n\n // Push fake entry to simplify cache bounds checks\n this.bMarks.push(s.length);\n this.eMarks.push(s.length);\n this.tShift.push(0);\n this.sCount.push(0);\n this.bsCount.push(0);\n\n this.lineMax = this.bMarks.length - 1; // don't count last fake line\n}\n\n// Push new token to \"stream\".\n//\nStateBlock.prototype.push = function (type, tag, nesting) {\n var token = new Token(type, tag, nesting);\n token.block = true;\n\n if (nesting < 0) this.level--; // closing tag\n token.level = this.level;\n if (nesting > 0) this.level++; // opening tag\n\n this.tokens.push(token);\n return token;\n};\n\nStateBlock.prototype.isEmpty = function isEmpty(line) {\n return this.bMarks[line] + this.tShift[line] >= this.eMarks[line];\n};\n\nStateBlock.prototype.skipEmptyLines = function skipEmptyLines(from) {\n for (var max = this.lineMax; from < max; from++) {\n if (this.bMarks[from] + this.tShift[from] < this.eMarks[from]) {\n break;\n }\n }\n return from;\n};\n\n// Skip spaces from given position.\nStateBlock.prototype.skipSpaces = function skipSpaces(pos) {\n var ch;\n\n for (var max = this.src.length; pos < max; pos++) {\n ch = this.src.charCodeAt(pos);\n if (!isSpace(ch)) { break; }\n }\n return pos;\n};\n\n// Skip spaces from given position in reverse.\nStateBlock.prototype.skipSpacesBack = function skipSpacesBack(pos, min) {\n if (pos <= min) { return pos; }\n\n while (pos > min) {\n if (!isSpace(this.src.charCodeAt(--pos))) { return pos + 1; }\n }\n return pos;\n};\n\n// Skip char codes from given position\nStateBlock.prototype.skipChars = function skipChars(pos, code) {\n for (var max = this.src.length; pos < max; pos++) {\n if (this.src.charCodeAt(pos) !== code) { break; }\n }\n return pos;\n};\n\n// Skip char codes reverse from given position - 1\nStateBlock.prototype.skipCharsBack = function skipCharsBack(pos, code, min) {\n if (pos <= min) { return pos; }\n\n while (pos > min) {\n if (code !== this.src.charCodeAt(--pos)) { return pos + 1; }\n }\n return pos;\n};\n\n// cut lines range from source.\nStateBlock.prototype.getLines = function getLines(begin, end, indent, keepLastLF) {\n var i, lineIndent, ch, first, last, queue, lineStart,\n line = begin;\n\n if (begin >= end) {\n return '';\n }\n\n queue = new Array(end - begin);\n\n for (i = 0; line < end; line++, i++) {\n lineIndent = 0;\n lineStart = first = this.bMarks[line];\n\n if (line + 1 < end || keepLastLF) {\n // No need for bounds check because we have fake entry on tail.\n last = this.eMarks[line] + 1;\n } else {\n last = this.eMarks[line];\n }\n\n while (first < last && lineIndent < indent) {\n ch = this.src.charCodeAt(first);\n\n if (isSpace(ch)) {\n if (ch === 0x09) {\n lineIndent += 4 - (lineIndent + this.bsCount[line]) % 4;\n } else {\n lineIndent++;\n }\n } else if (first - lineStart < this.tShift[line]) {\n // patched tShift masked characters to look like spaces (blockquotes, list markers)\n lineIndent++;\n } else {\n break;\n }\n\n first++;\n }\n\n if (lineIndent > indent) {\n // partially expanding tabs in code blocks, e.g '\\t\\tfoobar'\n // with indent=2 becomes ' \\tfoobar'\n queue[i] = new Array(lineIndent - indent + 1).join(' ') + this.src.slice(first, last);\n } else {\n queue[i] = this.src.slice(first, last);\n }\n }\n\n return queue.join('');\n};\n\n// re-export Token class to use in block rules\nStateBlock.prototype.Token = Token;\n\n\nmodule.exports = StateBlock;\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_block/state_block.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_block/table.js": -/*!***********************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_block/table.js ***! - \***********************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// GFM table, https://github.github.com/gfm/#tables-extension-\n\n\n\nvar isSpace = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").isSpace;\n\n\nfunction getLine(state, line) {\n var pos = state.bMarks[line] + state.tShift[line],\n max = state.eMarks[line];\n\n return state.src.substr(pos, max - pos);\n}\n\nfunction escapedSplit(str) {\n var result = [],\n pos = 0,\n max = str.length,\n ch,\n isEscaped = false,\n lastPos = 0,\n current = '';\n\n ch = str.charCodeAt(pos);\n\n while (pos < max) {\n if (ch === 0x7c/* | */) {\n if (!isEscaped) {\n // pipe separating cells, '|'\n result.push(current + str.substring(lastPos, pos));\n current = '';\n lastPos = pos + 1;\n } else {\n // escaped pipe, '\\|'\n current += str.substring(lastPos, pos - 1);\n lastPos = pos;\n }\n }\n\n isEscaped = (ch === 0x5c/* \\ */);\n pos++;\n\n ch = str.charCodeAt(pos);\n }\n\n result.push(current + str.substring(lastPos));\n\n return result;\n}\n\n\nmodule.exports = function table(state, startLine, endLine, silent) {\n var ch, lineText, pos, i, l, nextLine, columns, columnCount, token,\n aligns, t, tableLines, tbodyLines, oldParentType, terminate,\n terminatorRules;\n\n // should have at least two lines\n if (startLine + 2 > endLine) { return false; }\n\n nextLine = startLine + 1;\n\n if (state.sCount[nextLine] < state.blkIndent) { return false; }\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[nextLine] - state.blkIndent >= 4) { return false; }\n\n // first character of the second line should be '|', '-', ':',\n // and no other characters are allowed but spaces;\n // basically, this is the equivalent of /^[-:|][-:|\\s]*$/ regexp\n\n pos = state.bMarks[nextLine] + state.tShift[nextLine];\n if (pos >= state.eMarks[nextLine]) { return false; }\n\n ch = state.src.charCodeAt(pos++);\n if (ch !== 0x7C/* | */ && ch !== 0x2D/* - */ && ch !== 0x3A/* : */) { return false; }\n\n while (pos < state.eMarks[nextLine]) {\n ch = state.src.charCodeAt(pos);\n\n if (ch !== 0x7C/* | */ && ch !== 0x2D/* - */ && ch !== 0x3A/* : */ && !isSpace(ch)) { return false; }\n\n pos++;\n }\n\n lineText = getLine(state, startLine + 1);\n\n columns = lineText.split('|');\n aligns = [];\n for (i = 0; i < columns.length; i++) {\n t = columns[i].trim();\n if (!t) {\n // allow empty columns before and after table, but not in between columns;\n // e.g. allow ` |---| `, disallow ` ---||--- `\n if (i === 0 || i === columns.length - 1) {\n continue;\n } else {\n return false;\n }\n }\n\n if (!/^:?-+:?$/.test(t)) { return false; }\n if (t.charCodeAt(t.length - 1) === 0x3A/* : */) {\n aligns.push(t.charCodeAt(0) === 0x3A/* : */ ? 'center' : 'right');\n } else if (t.charCodeAt(0) === 0x3A/* : */) {\n aligns.push('left');\n } else {\n aligns.push('');\n }\n }\n\n lineText = getLine(state, startLine).trim();\n if (lineText.indexOf('|') === -1) { return false; }\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }\n columns = escapedSplit(lineText);\n if (columns.length && columns[0] === '') columns.shift();\n if (columns.length && columns[columns.length - 1] === '') columns.pop();\n\n // header row will define an amount of columns in the entire table,\n // and align row should be exactly the same (the rest of the rows can differ)\n columnCount = columns.length;\n if (columnCount === 0 || columnCount !== aligns.length) { return false; }\n\n if (silent) { return true; }\n\n oldParentType = state.parentType;\n state.parentType = 'table';\n\n // use 'blockquote' lists for termination because it's\n // the most similar to tables\n terminatorRules = state.md.block.ruler.getRules('blockquote');\n\n token = state.push('table_open', 'table', 1);\n token.map = tableLines = [ startLine, 0 ];\n\n token = state.push('thead_open', 'thead', 1);\n token.map = [ startLine, startLine + 1 ];\n\n token = state.push('tr_open', 'tr', 1);\n token.map = [ startLine, startLine + 1 ];\n\n for (i = 0; i < columns.length; i++) {\n token = state.push('th_open', 'th', 1);\n if (aligns[i]) {\n token.attrs = [ [ 'style', 'text-align:' + aligns[i] ] ];\n }\n\n token = state.push('inline', '', 0);\n token.content = columns[i].trim();\n token.children = [];\n\n token = state.push('th_close', 'th', -1);\n }\n\n token = state.push('tr_close', 'tr', -1);\n token = state.push('thead_close', 'thead', -1);\n\n for (nextLine = startLine + 2; nextLine < endLine; nextLine++) {\n if (state.sCount[nextLine] < state.blkIndent) { break; }\n\n terminate = false;\n for (i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n\n if (terminate) { break; }\n lineText = getLine(state, nextLine).trim();\n if (!lineText) { break; }\n if (state.sCount[nextLine] - state.blkIndent >= 4) { break; }\n columns = escapedSplit(lineText);\n if (columns.length && columns[0] === '') columns.shift();\n if (columns.length && columns[columns.length - 1] === '') columns.pop();\n\n if (nextLine === startLine + 2) {\n token = state.push('tbody_open', 'tbody', 1);\n token.map = tbodyLines = [ startLine + 2, 0 ];\n }\n\n token = state.push('tr_open', 'tr', 1);\n token.map = [ nextLine, nextLine + 1 ];\n\n for (i = 0; i < columnCount; i++) {\n token = state.push('td_open', 'td', 1);\n if (aligns[i]) {\n token.attrs = [ [ 'style', 'text-align:' + aligns[i] ] ];\n }\n\n token = state.push('inline', '', 0);\n token.content = columns[i] ? columns[i].trim() : '';\n token.children = [];\n\n token = state.push('td_close', 'td', -1);\n }\n token = state.push('tr_close', 'tr', -1);\n }\n\n if (tbodyLines) {\n token = state.push('tbody_close', 'tbody', -1);\n tbodyLines[1] = nextLine;\n }\n\n token = state.push('table_close', 'table', -1);\n tableLines[1] = nextLine;\n\n state.parentType = oldParentType;\n state.line = nextLine;\n return true;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_block/table.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_core/block.js": -/*!**********************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_core/block.js ***! - \**********************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("\n\n\nmodule.exports = function block(state) {\n var token;\n\n if (state.inlineMode) {\n token = new state.Token('inline', '', 0);\n token.content = state.src;\n token.map = [ 0, 1 ];\n token.children = [];\n state.tokens.push(token);\n } else {\n state.md.block.parse(state.src, state.md, state.env, state.tokens);\n }\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_core/block.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_core/inline.js": -/*!***********************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_core/inline.js ***! - \***********************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("\n\nmodule.exports = function inline(state) {\n var tokens = state.tokens, tok, i, l;\n\n // Parse inlines\n for (i = 0, l = tokens.length; i < l; i++) {\n tok = tokens[i];\n if (tok.type === 'inline') {\n state.md.inline.parse(tok.content, state.md, state.env, tok.children);\n }\n }\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_core/inline.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_core/linkify.js": -/*!************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_core/linkify.js ***! - \************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Replace link-like texts with link nodes.\n//\n// Currently restricted by `md.validateLink()` to http/https/ftp\n//\n\n\n\nvar arrayReplaceAt = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").arrayReplaceAt;\n\n\nfunction isLinkOpen(str) {\n return /^\\s]/i.test(str);\n}\nfunction isLinkClose(str) {\n return /^<\\/a\\s*>/i.test(str);\n}\n\n\nmodule.exports = function linkify(state) {\n var i, j, l, tokens, token, currentToken, nodes, ln, text, pos, lastPos,\n level, htmlLinkLevel, url, fullUrl, urlText,\n blockTokens = state.tokens,\n links;\n\n if (!state.md.options.linkify) { return; }\n\n for (j = 0, l = blockTokens.length; j < l; j++) {\n if (blockTokens[j].type !== 'inline' ||\n !state.md.linkify.pretest(blockTokens[j].content)) {\n continue;\n }\n\n tokens = blockTokens[j].children;\n\n htmlLinkLevel = 0;\n\n // We scan from the end, to keep position when new tags added.\n // Use reversed logic in links start/end match\n for (i = tokens.length - 1; i >= 0; i--) {\n currentToken = tokens[i];\n\n // Skip content of markdown links\n if (currentToken.type === 'link_close') {\n i--;\n while (tokens[i].level !== currentToken.level && tokens[i].type !== 'link_open') {\n i--;\n }\n continue;\n }\n\n // Skip content of html tag links\n if (currentToken.type === 'html_inline') {\n if (isLinkOpen(currentToken.content) && htmlLinkLevel > 0) {\n htmlLinkLevel--;\n }\n if (isLinkClose(currentToken.content)) {\n htmlLinkLevel++;\n }\n }\n if (htmlLinkLevel > 0) { continue; }\n\n if (currentToken.type === 'text' && state.md.linkify.test(currentToken.content)) {\n\n text = currentToken.content;\n links = state.md.linkify.match(text);\n\n // Now split string to nodes\n nodes = [];\n level = currentToken.level;\n lastPos = 0;\n\n for (ln = 0; ln < links.length; ln++) {\n\n url = links[ln].url;\n fullUrl = state.md.normalizeLink(url);\n if (!state.md.validateLink(fullUrl)) { continue; }\n\n urlText = links[ln].text;\n\n // Linkifier might send raw hostnames like \"example.com\", where url\n // starts with domain name. So we prepend http:// in those cases,\n // and remove it afterwards.\n //\n if (!links[ln].schema) {\n urlText = state.md.normalizeLinkText('http://' + urlText).replace(/^http:\\/\\//, '');\n } else if (links[ln].schema === 'mailto:' && !/^mailto:/i.test(urlText)) {\n urlText = state.md.normalizeLinkText('mailto:' + urlText).replace(/^mailto:/, '');\n } else {\n urlText = state.md.normalizeLinkText(urlText);\n }\n\n pos = links[ln].index;\n\n if (pos > lastPos) {\n token = new state.Token('text', '', 0);\n token.content = text.slice(lastPos, pos);\n token.level = level;\n nodes.push(token);\n }\n\n token = new state.Token('link_open', 'a', 1);\n token.attrs = [ [ 'href', fullUrl ] ];\n token.level = level++;\n token.markup = 'linkify';\n token.info = 'auto';\n nodes.push(token);\n\n token = new state.Token('text', '', 0);\n token.content = urlText;\n token.level = level;\n nodes.push(token);\n\n token = new state.Token('link_close', 'a', -1);\n token.level = --level;\n token.markup = 'linkify';\n token.info = 'auto';\n nodes.push(token);\n\n lastPos = links[ln].lastIndex;\n }\n if (lastPos < text.length) {\n token = new state.Token('text', '', 0);\n token.content = text.slice(lastPos);\n token.level = level;\n nodes.push(token);\n }\n\n // replace current node\n blockTokens[j].children = tokens = arrayReplaceAt(tokens, i, nodes);\n }\n }\n }\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_core/linkify.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_core/normalize.js": -/*!**************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_core/normalize.js ***! - \**************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Normalize input string\n\n\n\n\n// https://spec.commonmark.org/0.29/#line-ending\nvar NEWLINES_RE = /\\r\\n?|\\n/g;\nvar NULL_RE = /\\0/g;\n\n\nmodule.exports = function normalize(state) {\n var str;\n\n // Normalize newlines\n str = state.src.replace(NEWLINES_RE, '\\n');\n\n // Replace NULL characters\n str = str.replace(NULL_RE, '\\uFFFD');\n\n state.src = str;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_core/normalize.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_core/replacements.js": -/*!*****************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_core/replacements.js ***! - \*****************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Simple typographic replacements\n//\n// (c) (C) → ©\n// (tm) (TM) → ™\n// (r) (R) → ®\n// +- → ±\n// (p) (P) -> §\n// ... → … (also ?.... → ?.., !.... → !..)\n// ???????? → ???, !!!!! → !!!, `,,` → `,`\n// -- → –, --- → —\n//\n\n\n// TODO:\n// - fractionals 1/2, 1/4, 3/4 -> ½, ¼, ¾\n// - miltiplication 2 x 4 -> 2 × 4\n\nvar RARE_RE = /\\+-|\\.\\.|\\?\\?\\?\\?|!!!!|,,|--/;\n\n// Workaround for phantomjs - need regex without /g flag,\n// or root check will fail every second time\nvar SCOPED_ABBR_TEST_RE = /\\((c|tm|r|p)\\)/i;\n\nvar SCOPED_ABBR_RE = /\\((c|tm|r|p)\\)/ig;\nvar SCOPED_ABBR = {\n c: '©',\n r: '®',\n p: '§',\n tm: '™'\n};\n\nfunction replaceFn(match, name) {\n return SCOPED_ABBR[name.toLowerCase()];\n}\n\nfunction replace_scoped(inlineTokens) {\n var i, token, inside_autolink = 0;\n\n for (i = inlineTokens.length - 1; i >= 0; i--) {\n token = inlineTokens[i];\n\n if (token.type === 'text' && !inside_autolink) {\n token.content = token.content.replace(SCOPED_ABBR_RE, replaceFn);\n }\n\n if (token.type === 'link_open' && token.info === 'auto') {\n inside_autolink--;\n }\n\n if (token.type === 'link_close' && token.info === 'auto') {\n inside_autolink++;\n }\n }\n}\n\nfunction replace_rare(inlineTokens) {\n var i, token, inside_autolink = 0;\n\n for (i = inlineTokens.length - 1; i >= 0; i--) {\n token = inlineTokens[i];\n\n if (token.type === 'text' && !inside_autolink) {\n if (RARE_RE.test(token.content)) {\n token.content = token.content\n .replace(/\\+-/g, '±')\n // .., ..., ....... -> …\n // but ?..... & !..... -> ?.. & !..\n .replace(/\\.{2,}/g, '…').replace(/([?!])…/g, '$1..')\n .replace(/([?!]){4,}/g, '$1$1$1').replace(/,{2,}/g, ',')\n // em-dash\n .replace(/(^|[^-])---(?=[^-]|$)/mg, '$1\\u2014')\n // en-dash\n .replace(/(^|\\s)--(?=\\s|$)/mg, '$1\\u2013')\n .replace(/(^|[^-\\s])--(?=[^-\\s]|$)/mg, '$1\\u2013');\n }\n }\n\n if (token.type === 'link_open' && token.info === 'auto') {\n inside_autolink--;\n }\n\n if (token.type === 'link_close' && token.info === 'auto') {\n inside_autolink++;\n }\n }\n}\n\n\nmodule.exports = function replace(state) {\n var blkIdx;\n\n if (!state.md.options.typographer) { return; }\n\n for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {\n\n if (state.tokens[blkIdx].type !== 'inline') { continue; }\n\n if (SCOPED_ABBR_TEST_RE.test(state.tokens[blkIdx].content)) {\n replace_scoped(state.tokens[blkIdx].children);\n }\n\n if (RARE_RE.test(state.tokens[blkIdx].content)) {\n replace_rare(state.tokens[blkIdx].children);\n }\n\n }\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_core/replacements.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_core/smartquotes.js": -/*!****************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_core/smartquotes.js ***! - \****************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Convert straight quotation marks to typographic ones\n//\n\n\n\nvar isWhiteSpace = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").isWhiteSpace;\nvar isPunctChar = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").isPunctChar;\nvar isMdAsciiPunct = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").isMdAsciiPunct;\n\nvar QUOTE_TEST_RE = /['\"]/;\nvar QUOTE_RE = /['\"]/g;\nvar APOSTROPHE = '\\u2019'; /* ’ */\n\n\nfunction replaceAt(str, index, ch) {\n return str.substr(0, index) + ch + str.substr(index + 1);\n}\n\nfunction process_inlines(tokens, state) {\n var i, token, text, t, pos, max, thisLevel, item, lastChar, nextChar,\n isLastPunctChar, isNextPunctChar, isLastWhiteSpace, isNextWhiteSpace,\n canOpen, canClose, j, isSingle, stack, openQuote, closeQuote;\n\n stack = [];\n\n for (i = 0; i < tokens.length; i++) {\n token = tokens[i];\n\n thisLevel = tokens[i].level;\n\n for (j = stack.length - 1; j >= 0; j--) {\n if (stack[j].level <= thisLevel) { break; }\n }\n stack.length = j + 1;\n\n if (token.type !== 'text') { continue; }\n\n text = token.content;\n pos = 0;\n max = text.length;\n\n /*eslint no-labels:0,block-scoped-var:0*/\n OUTER:\n while (pos < max) {\n QUOTE_RE.lastIndex = pos;\n t = QUOTE_RE.exec(text);\n if (!t) { break; }\n\n canOpen = canClose = true;\n pos = t.index + 1;\n isSingle = (t[0] === \"'\");\n\n // Find previous character,\n // default to space if it's the beginning of the line\n //\n lastChar = 0x20;\n\n if (t.index - 1 >= 0) {\n lastChar = text.charCodeAt(t.index - 1);\n } else {\n for (j = i - 1; j >= 0; j--) {\n if (tokens[j].type === 'softbreak' || tokens[j].type === 'hardbreak') break; // lastChar defaults to 0x20\n if (!tokens[j].content) continue; // should skip all tokens except 'text', 'html_inline' or 'code_inline'\n\n lastChar = tokens[j].content.charCodeAt(tokens[j].content.length - 1);\n break;\n }\n }\n\n // Find next character,\n // default to space if it's the end of the line\n //\n nextChar = 0x20;\n\n if (pos < max) {\n nextChar = text.charCodeAt(pos);\n } else {\n for (j = i + 1; j < tokens.length; j++) {\n if (tokens[j].type === 'softbreak' || tokens[j].type === 'hardbreak') break; // nextChar defaults to 0x20\n if (!tokens[j].content) continue; // should skip all tokens except 'text', 'html_inline' or 'code_inline'\n\n nextChar = tokens[j].content.charCodeAt(0);\n break;\n }\n }\n\n isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar));\n isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar));\n\n isLastWhiteSpace = isWhiteSpace(lastChar);\n isNextWhiteSpace = isWhiteSpace(nextChar);\n\n if (isNextWhiteSpace) {\n canOpen = false;\n } else if (isNextPunctChar) {\n if (!(isLastWhiteSpace || isLastPunctChar)) {\n canOpen = false;\n }\n }\n\n if (isLastWhiteSpace) {\n canClose = false;\n } else if (isLastPunctChar) {\n if (!(isNextWhiteSpace || isNextPunctChar)) {\n canClose = false;\n }\n }\n\n if (nextChar === 0x22 /* \" */ && t[0] === '\"') {\n if (lastChar >= 0x30 /* 0 */ && lastChar <= 0x39 /* 9 */) {\n // special case: 1\"\" - count first quote as an inch\n canClose = canOpen = false;\n }\n }\n\n if (canOpen && canClose) {\n // Replace quotes in the middle of punctuation sequence, but not\n // in the middle of the words, i.e.:\n //\n // 1. foo \" bar \" baz - not replaced\n // 2. foo-\"-bar-\"-baz - replaced\n // 3. foo\"bar\"baz - not replaced\n //\n canOpen = isLastPunctChar;\n canClose = isNextPunctChar;\n }\n\n if (!canOpen && !canClose) {\n // middle of word\n if (isSingle) {\n token.content = replaceAt(token.content, t.index, APOSTROPHE);\n }\n continue;\n }\n\n if (canClose) {\n // this could be a closing quote, rewind the stack to get a match\n for (j = stack.length - 1; j >= 0; j--) {\n item = stack[j];\n if (stack[j].level < thisLevel) { break; }\n if (item.single === isSingle && stack[j].level === thisLevel) {\n item = stack[j];\n\n if (isSingle) {\n openQuote = state.md.options.quotes[2];\n closeQuote = state.md.options.quotes[3];\n } else {\n openQuote = state.md.options.quotes[0];\n closeQuote = state.md.options.quotes[1];\n }\n\n // replace token.content *before* tokens[item.token].content,\n // because, if they are pointing at the same token, replaceAt\n // could mess up indices when quote length != 1\n token.content = replaceAt(token.content, t.index, closeQuote);\n tokens[item.token].content = replaceAt(\n tokens[item.token].content, item.pos, openQuote);\n\n pos += closeQuote.length - 1;\n if (item.token === i) { pos += openQuote.length - 1; }\n\n text = token.content;\n max = text.length;\n\n stack.length = j;\n continue OUTER;\n }\n }\n }\n\n if (canOpen) {\n stack.push({\n token: i,\n pos: t.index,\n single: isSingle,\n level: thisLevel\n });\n } else if (canClose && isSingle) {\n token.content = replaceAt(token.content, t.index, APOSTROPHE);\n }\n }\n }\n}\n\n\nmodule.exports = function smartquotes(state) {\n /*eslint max-depth:0*/\n var blkIdx;\n\n if (!state.md.options.typographer) { return; }\n\n for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {\n\n if (state.tokens[blkIdx].type !== 'inline' ||\n !QUOTE_TEST_RE.test(state.tokens[blkIdx].content)) {\n continue;\n }\n\n process_inlines(state.tokens[blkIdx].children, state);\n }\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_core/smartquotes.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_core/state_core.js": -/*!***************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_core/state_core.js ***! - \***************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Core state object\n//\n\n\nvar Token = __webpack_require__(/*! ../token */ \"./node_modules/markdown-it/lib/token.js\");\n\n\nfunction StateCore(src, md, env) {\n this.src = src;\n this.env = env;\n this.tokens = [];\n this.inlineMode = false;\n this.md = md; // link to parser instance\n}\n\n// re-export Token class to use in core rules\nStateCore.prototype.Token = Token;\n\n\nmodule.exports = StateCore;\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_core/state_core.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_inline/autolink.js": -/*!***************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_inline/autolink.js ***! - \***************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Process autolinks ''\n\n\n\n\n/*eslint max-len:0*/\nvar EMAIL_RE = /^([a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)$/;\nvar AUTOLINK_RE = /^([a-zA-Z][a-zA-Z0-9+.\\-]{1,31}):([^<>\\x00-\\x20]*)$/;\n\n\nmodule.exports = function autolink(state, silent) {\n var url, fullUrl, token, ch, start, max,\n pos = state.pos;\n\n if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false; }\n\n start = state.pos;\n max = state.posMax;\n\n for (;;) {\n if (++pos >= max) return false;\n\n ch = state.src.charCodeAt(pos);\n\n if (ch === 0x3C /* < */) return false;\n if (ch === 0x3E /* > */) break;\n }\n\n url = state.src.slice(start + 1, pos);\n\n if (AUTOLINK_RE.test(url)) {\n fullUrl = state.md.normalizeLink(url);\n if (!state.md.validateLink(fullUrl)) { return false; }\n\n if (!silent) {\n token = state.push('link_open', 'a', 1);\n token.attrs = [ [ 'href', fullUrl ] ];\n token.markup = 'autolink';\n token.info = 'auto';\n\n token = state.push('text', '', 0);\n token.content = state.md.normalizeLinkText(url);\n\n token = state.push('link_close', 'a', -1);\n token.markup = 'autolink';\n token.info = 'auto';\n }\n\n state.pos += url.length + 2;\n return true;\n }\n\n if (EMAIL_RE.test(url)) {\n fullUrl = state.md.normalizeLink('mailto:' + url);\n if (!state.md.validateLink(fullUrl)) { return false; }\n\n if (!silent) {\n token = state.push('link_open', 'a', 1);\n token.attrs = [ [ 'href', fullUrl ] ];\n token.markup = 'autolink';\n token.info = 'auto';\n\n token = state.push('text', '', 0);\n token.content = state.md.normalizeLinkText(url);\n\n token = state.push('link_close', 'a', -1);\n token.markup = 'autolink';\n token.info = 'auto';\n }\n\n state.pos += url.length + 2;\n return true;\n }\n\n return false;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_inline/autolink.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_inline/backticks.js": -/*!****************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_inline/backticks.js ***! - \****************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Parse backticks\n\n\n\n\nmodule.exports = function backtick(state, silent) {\n var start, max, marker, token, matchStart, matchEnd, openerLength, closerLength,\n pos = state.pos,\n ch = state.src.charCodeAt(pos);\n\n if (ch !== 0x60/* ` */) { return false; }\n\n start = pos;\n pos++;\n max = state.posMax;\n\n // scan marker length\n while (pos < max && state.src.charCodeAt(pos) === 0x60/* ` */) { pos++; }\n\n marker = state.src.slice(start, pos);\n openerLength = marker.length;\n\n if (state.backticksScanned && (state.backticks[openerLength] || 0) <= start) {\n if (!silent) state.pending += marker;\n state.pos += openerLength;\n return true;\n }\n\n matchStart = matchEnd = pos;\n\n // Nothing found in the cache, scan until the end of the line (or until marker is found)\n while ((matchStart = state.src.indexOf('`', matchEnd)) !== -1) {\n matchEnd = matchStart + 1;\n\n // scan marker length\n while (matchEnd < max && state.src.charCodeAt(matchEnd) === 0x60/* ` */) { matchEnd++; }\n\n closerLength = matchEnd - matchStart;\n\n if (closerLength === openerLength) {\n // Found matching closer length.\n if (!silent) {\n token = state.push('code_inline', 'code', 0);\n token.markup = marker;\n token.content = state.src.slice(pos, matchStart)\n .replace(/\\n/g, ' ')\n .replace(/^ (.+) $/, '$1');\n }\n state.pos = matchEnd;\n return true;\n }\n\n // Some different length found, put it in cache as upper limit of where closer can be found\n state.backticks[closerLength] = matchStart;\n }\n\n // Scanned through the end, didn't find anything\n state.backticksScanned = true;\n\n if (!silent) state.pending += marker;\n state.pos += openerLength;\n return true;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_inline/backticks.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_inline/balance_pairs.js": -/*!********************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_inline/balance_pairs.js ***! - \********************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// For each opening emphasis-like marker find a matching closing one\n//\n\n\n\nfunction processDelimiters(state, delimiters) {\n var closerIdx, openerIdx, closer, opener, minOpenerIdx, newMinOpenerIdx,\n isOddMatch, lastJump,\n openersBottom = {},\n max = delimiters.length;\n\n for (closerIdx = 0; closerIdx < max; closerIdx++) {\n closer = delimiters[closerIdx];\n\n // Length is only used for emphasis-specific \"rule of 3\",\n // if it's not defined (in strikethrough or 3rd party plugins),\n // we can default it to 0 to disable those checks.\n //\n closer.length = closer.length || 0;\n\n if (!closer.close) continue;\n\n // Previously calculated lower bounds (previous fails)\n // for each marker and each delimiter length modulo 3.\n if (!openersBottom.hasOwnProperty(closer.marker)) {\n openersBottom[closer.marker] = [ -1, -1, -1 ];\n }\n\n minOpenerIdx = openersBottom[closer.marker][closer.length % 3];\n\n openerIdx = closerIdx - closer.jump - 1;\n newMinOpenerIdx = openerIdx;\n\n for (; openerIdx > minOpenerIdx; openerIdx -= opener.jump + 1) {\n opener = delimiters[openerIdx];\n\n if (opener.marker !== closer.marker) continue;\n\n if (opener.open && opener.end < 0) {\n\n isOddMatch = false;\n\n // from spec:\n //\n // If one of the delimiters can both open and close emphasis, then the\n // sum of the lengths of the delimiter runs containing the opening and\n // closing delimiters must not be a multiple of 3 unless both lengths\n // are multiples of 3.\n //\n if (opener.close || closer.open) {\n if ((opener.length + closer.length) % 3 === 0) {\n if (opener.length % 3 !== 0 || closer.length % 3 !== 0) {\n isOddMatch = true;\n }\n }\n }\n\n if (!isOddMatch) {\n // If previous delimiter cannot be an opener, we can safely skip\n // the entire sequence in future checks. This is required to make\n // sure algorithm has linear complexity (see *_*_*_*_*_... case).\n //\n lastJump = openerIdx > 0 && !delimiters[openerIdx - 1].open ?\n delimiters[openerIdx - 1].jump + 1 :\n 0;\n\n closer.jump = closerIdx - openerIdx + lastJump;\n closer.open = false;\n opener.end = closerIdx;\n opener.jump = lastJump;\n opener.close = false;\n newMinOpenerIdx = -1;\n break;\n }\n }\n }\n\n if (newMinOpenerIdx !== -1) {\n // If match for this delimiter run failed, we want to set lower bound for\n // future lookups. This is required to make sure algorithm has linear\n // complexity.\n //\n // See details here:\n // https://github.com/commonmark/cmark/issues/178#issuecomment-270417442\n //\n openersBottom[closer.marker][(closer.length || 0) % 3] = newMinOpenerIdx;\n }\n }\n}\n\n\nmodule.exports = function link_pairs(state) {\n var curr,\n tokens_meta = state.tokens_meta,\n max = state.tokens_meta.length;\n\n processDelimiters(state, state.delimiters);\n\n for (curr = 0; curr < max; curr++) {\n if (tokens_meta[curr] && tokens_meta[curr].delimiters) {\n processDelimiters(state, tokens_meta[curr].delimiters);\n }\n }\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_inline/balance_pairs.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_inline/emphasis.js": -/*!***************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_inline/emphasis.js ***! - \***************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Process *this* and _that_\n//\n\n\n\n// Insert each marker as a separate text token, and add it to delimiter list\n//\nmodule.exports.tokenize = function emphasis(state, silent) {\n var i, scanned, token,\n start = state.pos,\n marker = state.src.charCodeAt(start);\n\n if (silent) { return false; }\n\n if (marker !== 0x5F /* _ */ && marker !== 0x2A /* * */) { return false; }\n\n scanned = state.scanDelims(state.pos, marker === 0x2A);\n\n for (i = 0; i < scanned.length; i++) {\n token = state.push('text', '', 0);\n token.content = String.fromCharCode(marker);\n\n state.delimiters.push({\n // Char code of the starting marker (number).\n //\n marker: marker,\n\n // Total length of these series of delimiters.\n //\n length: scanned.length,\n\n // An amount of characters before this one that's equivalent to\n // current one. In plain English: if this delimiter does not open\n // an emphasis, neither do previous `jump` characters.\n //\n // Used to skip sequences like \"*****\" in one step, for 1st asterisk\n // value will be 0, for 2nd it's 1 and so on.\n //\n jump: i,\n\n // A position of the token this delimiter corresponds to.\n //\n token: state.tokens.length - 1,\n\n // If this delimiter is matched as a valid opener, `end` will be\n // equal to its position, otherwise it's `-1`.\n //\n end: -1,\n\n // Boolean flags that determine if this delimiter could open or close\n // an emphasis.\n //\n open: scanned.can_open,\n close: scanned.can_close\n });\n }\n\n state.pos += scanned.length;\n\n return true;\n};\n\n\nfunction postProcess(state, delimiters) {\n var i,\n startDelim,\n endDelim,\n token,\n ch,\n isStrong,\n max = delimiters.length;\n\n for (i = max - 1; i >= 0; i--) {\n startDelim = delimiters[i];\n\n if (startDelim.marker !== 0x5F/* _ */ && startDelim.marker !== 0x2A/* * */) {\n continue;\n }\n\n // Process only opening markers\n if (startDelim.end === -1) {\n continue;\n }\n\n endDelim = delimiters[startDelim.end];\n\n // If the previous delimiter has the same marker and is adjacent to this one,\n // merge those into one strong delimiter.\n //\n // `whatever` -> `whatever`\n //\n isStrong = i > 0 &&\n delimiters[i - 1].end === startDelim.end + 1 &&\n delimiters[i - 1].token === startDelim.token - 1 &&\n delimiters[startDelim.end + 1].token === endDelim.token + 1 &&\n delimiters[i - 1].marker === startDelim.marker;\n\n ch = String.fromCharCode(startDelim.marker);\n\n token = state.tokens[startDelim.token];\n token.type = isStrong ? 'strong_open' : 'em_open';\n token.tag = isStrong ? 'strong' : 'em';\n token.nesting = 1;\n token.markup = isStrong ? ch + ch : ch;\n token.content = '';\n\n token = state.tokens[endDelim.token];\n token.type = isStrong ? 'strong_close' : 'em_close';\n token.tag = isStrong ? 'strong' : 'em';\n token.nesting = -1;\n token.markup = isStrong ? ch + ch : ch;\n token.content = '';\n\n if (isStrong) {\n state.tokens[delimiters[i - 1].token].content = '';\n state.tokens[delimiters[startDelim.end + 1].token].content = '';\n i--;\n }\n }\n}\n\n\n// Walk through delimiter list and replace text tokens with tags\n//\nmodule.exports.postProcess = function emphasis(state) {\n var curr,\n tokens_meta = state.tokens_meta,\n max = state.tokens_meta.length;\n\n postProcess(state, state.delimiters);\n\n for (curr = 0; curr < max; curr++) {\n if (tokens_meta[curr] && tokens_meta[curr].delimiters) {\n postProcess(state, tokens_meta[curr].delimiters);\n }\n }\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_inline/emphasis.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_inline/entity.js": -/*!*************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_inline/entity.js ***! - \*************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Process html entity - {, ¯, ", ...\n\n\n\nvar entities = __webpack_require__(/*! ../common/entities */ \"./node_modules/markdown-it/lib/common/entities.js\");\nvar has = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").has;\nvar isValidEntityCode = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").isValidEntityCode;\nvar fromCodePoint = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").fromCodePoint;\n\n\nvar DIGITAL_RE = /^&#((?:x[a-f0-9]{1,6}|[0-9]{1,7}));/i;\nvar NAMED_RE = /^&([a-z][a-z0-9]{1,31});/i;\n\n\nmodule.exports = function entity(state, silent) {\n var ch, code, match, pos = state.pos, max = state.posMax;\n\n if (state.src.charCodeAt(pos) !== 0x26/* & */) { return false; }\n\n if (pos + 1 < max) {\n ch = state.src.charCodeAt(pos + 1);\n\n if (ch === 0x23 /* # */) {\n match = state.src.slice(pos).match(DIGITAL_RE);\n if (match) {\n if (!silent) {\n code = match[1][0].toLowerCase() === 'x' ? parseInt(match[1].slice(1), 16) : parseInt(match[1], 10);\n state.pending += isValidEntityCode(code) ? fromCodePoint(code) : fromCodePoint(0xFFFD);\n }\n state.pos += match[0].length;\n return true;\n }\n } else {\n match = state.src.slice(pos).match(NAMED_RE);\n if (match) {\n if (has(entities, match[1])) {\n if (!silent) { state.pending += entities[match[1]]; }\n state.pos += match[0].length;\n return true;\n }\n }\n }\n }\n\n if (!silent) { state.pending += '&'; }\n state.pos++;\n return true;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_inline/entity.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_inline/escape.js": -/*!*************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_inline/escape.js ***! - \*************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Process escaped chars and hardbreaks\n\n\n\nvar isSpace = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").isSpace;\n\nvar ESCAPED = [];\n\nfor (var i = 0; i < 256; i++) { ESCAPED.push(0); }\n\n'\\\\!\"#$%&\\'()*+,./:;<=>?@[]^_`{|}~-'\n .split('').forEach(function (ch) { ESCAPED[ch.charCodeAt(0)] = 1; });\n\n\nmodule.exports = function escape(state, silent) {\n var ch, pos = state.pos, max = state.posMax;\n\n if (state.src.charCodeAt(pos) !== 0x5C/* \\ */) { return false; }\n\n pos++;\n\n if (pos < max) {\n ch = state.src.charCodeAt(pos);\n\n if (ch < 256 && ESCAPED[ch] !== 0) {\n if (!silent) { state.pending += state.src[pos]; }\n state.pos += 2;\n return true;\n }\n\n if (ch === 0x0A) {\n if (!silent) {\n state.push('hardbreak', 'br', 0);\n }\n\n pos++;\n // skip leading whitespaces from next line\n while (pos < max) {\n ch = state.src.charCodeAt(pos);\n if (!isSpace(ch)) { break; }\n pos++;\n }\n\n state.pos = pos;\n return true;\n }\n }\n\n if (!silent) { state.pending += '\\\\'; }\n state.pos++;\n return true;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_inline/escape.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_inline/html_inline.js": -/*!******************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_inline/html_inline.js ***! - \******************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Process html tags\n\n\n\n\nvar HTML_TAG_RE = __webpack_require__(/*! ../common/html_re */ \"./node_modules/markdown-it/lib/common/html_re.js\").HTML_TAG_RE;\n\n\nfunction isLetter(ch) {\n /*eslint no-bitwise:0*/\n var lc = ch | 0x20; // to lower case\n return (lc >= 0x61/* a */) && (lc <= 0x7a/* z */);\n}\n\n\nmodule.exports = function html_inline(state, silent) {\n var ch, match, max, token,\n pos = state.pos;\n\n if (!state.md.options.html) { return false; }\n\n // Check start\n max = state.posMax;\n if (state.src.charCodeAt(pos) !== 0x3C/* < */ ||\n pos + 2 >= max) {\n return false;\n }\n\n // Quick fail on second char\n ch = state.src.charCodeAt(pos + 1);\n if (ch !== 0x21/* ! */ &&\n ch !== 0x3F/* ? */ &&\n ch !== 0x2F/* / */ &&\n !isLetter(ch)) {\n return false;\n }\n\n match = state.src.slice(pos).match(HTML_TAG_RE);\n if (!match) { return false; }\n\n if (!silent) {\n token = state.push('html_inline', '', 0);\n token.content = state.src.slice(pos, pos + match[0].length);\n }\n state.pos += match[0].length;\n return true;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_inline/html_inline.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_inline/image.js": -/*!************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_inline/image.js ***! - \************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Process ![image]( \"title\")\n\n\n\nvar normalizeReference = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").normalizeReference;\nvar isSpace = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").isSpace;\n\n\nmodule.exports = function image(state, silent) {\n var attrs,\n code,\n content,\n label,\n labelEnd,\n labelStart,\n pos,\n ref,\n res,\n title,\n token,\n tokens,\n start,\n href = '',\n oldPos = state.pos,\n max = state.posMax;\n\n if (state.src.charCodeAt(state.pos) !== 0x21/* ! */) { return false; }\n if (state.src.charCodeAt(state.pos + 1) !== 0x5B/* [ */) { return false; }\n\n labelStart = state.pos + 2;\n labelEnd = state.md.helpers.parseLinkLabel(state, state.pos + 1, false);\n\n // parser failed to find ']', so it's not a valid link\n if (labelEnd < 0) { return false; }\n\n pos = labelEnd + 1;\n if (pos < max && state.src.charCodeAt(pos) === 0x28/* ( */) {\n //\n // Inline link\n //\n\n // [link]( \"title\" )\n // ^^ skipping these spaces\n pos++;\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (!isSpace(code) && code !== 0x0A) { break; }\n }\n if (pos >= max) { return false; }\n\n // [link]( \"title\" )\n // ^^^^^^ parsing link destination\n start = pos;\n res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax);\n if (res.ok) {\n href = state.md.normalizeLink(res.str);\n if (state.md.validateLink(href)) {\n pos = res.pos;\n } else {\n href = '';\n }\n }\n\n // [link]( \"title\" )\n // ^^ skipping these spaces\n start = pos;\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (!isSpace(code) && code !== 0x0A) { break; }\n }\n\n // [link]( \"title\" )\n // ^^^^^^^ parsing link title\n res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax);\n if (pos < max && start !== pos && res.ok) {\n title = res.str;\n pos = res.pos;\n\n // [link]( \"title\" )\n // ^^ skipping these spaces\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (!isSpace(code) && code !== 0x0A) { break; }\n }\n } else {\n title = '';\n }\n\n if (pos >= max || state.src.charCodeAt(pos) !== 0x29/* ) */) {\n state.pos = oldPos;\n return false;\n }\n pos++;\n } else {\n //\n // Link reference\n //\n if (typeof state.env.references === 'undefined') { return false; }\n\n if (pos < max && state.src.charCodeAt(pos) === 0x5B/* [ */) {\n start = pos + 1;\n pos = state.md.helpers.parseLinkLabel(state, pos);\n if (pos >= 0) {\n label = state.src.slice(start, pos++);\n } else {\n pos = labelEnd + 1;\n }\n } else {\n pos = labelEnd + 1;\n }\n\n // covers label === '' and label === undefined\n // (collapsed reference link and shortcut reference link respectively)\n if (!label) { label = state.src.slice(labelStart, labelEnd); }\n\n ref = state.env.references[normalizeReference(label)];\n if (!ref) {\n state.pos = oldPos;\n return false;\n }\n href = ref.href;\n title = ref.title;\n }\n\n //\n // We found the end of the link, and know for a fact it's a valid link;\n // so all that's left to do is to call tokenizer.\n //\n if (!silent) {\n content = state.src.slice(labelStart, labelEnd);\n\n state.md.inline.parse(\n content,\n state.md,\n state.env,\n tokens = []\n );\n\n token = state.push('image', 'img', 0);\n token.attrs = attrs = [ [ 'src', href ], [ 'alt', '' ] ];\n token.children = tokens;\n token.content = content;\n\n if (title) {\n attrs.push([ 'title', title ]);\n }\n }\n\n state.pos = pos;\n state.posMax = max;\n return true;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_inline/image.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_inline/link.js": -/*!***********************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_inline/link.js ***! - \***********************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Process [link]( \"stuff\")\n\n\n\nvar normalizeReference = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").normalizeReference;\nvar isSpace = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").isSpace;\n\n\nmodule.exports = function link(state, silent) {\n var attrs,\n code,\n label,\n labelEnd,\n labelStart,\n pos,\n res,\n ref,\n token,\n href = '',\n title = '',\n oldPos = state.pos,\n max = state.posMax,\n start = state.pos,\n parseReference = true;\n\n if (state.src.charCodeAt(state.pos) !== 0x5B/* [ */) { return false; }\n\n labelStart = state.pos + 1;\n labelEnd = state.md.helpers.parseLinkLabel(state, state.pos, true);\n\n // parser failed to find ']', so it's not a valid link\n if (labelEnd < 0) { return false; }\n\n pos = labelEnd + 1;\n if (pos < max && state.src.charCodeAt(pos) === 0x28/* ( */) {\n //\n // Inline link\n //\n\n // might have found a valid shortcut link, disable reference parsing\n parseReference = false;\n\n // [link]( \"title\" )\n // ^^ skipping these spaces\n pos++;\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (!isSpace(code) && code !== 0x0A) { break; }\n }\n if (pos >= max) { return false; }\n\n // [link]( \"title\" )\n // ^^^^^^ parsing link destination\n start = pos;\n res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax);\n if (res.ok) {\n href = state.md.normalizeLink(res.str);\n if (state.md.validateLink(href)) {\n pos = res.pos;\n } else {\n href = '';\n }\n\n // [link]( \"title\" )\n // ^^ skipping these spaces\n start = pos;\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (!isSpace(code) && code !== 0x0A) { break; }\n }\n\n // [link]( \"title\" )\n // ^^^^^^^ parsing link title\n res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax);\n if (pos < max && start !== pos && res.ok) {\n title = res.str;\n pos = res.pos;\n\n // [link]( \"title\" )\n // ^^ skipping these spaces\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (!isSpace(code) && code !== 0x0A) { break; }\n }\n }\n }\n\n if (pos >= max || state.src.charCodeAt(pos) !== 0x29/* ) */) {\n // parsing a valid shortcut link failed, fallback to reference\n parseReference = true;\n }\n pos++;\n }\n\n if (parseReference) {\n //\n // Link reference\n //\n if (typeof state.env.references === 'undefined') { return false; }\n\n if (pos < max && state.src.charCodeAt(pos) === 0x5B/* [ */) {\n start = pos + 1;\n pos = state.md.helpers.parseLinkLabel(state, pos);\n if (pos >= 0) {\n label = state.src.slice(start, pos++);\n } else {\n pos = labelEnd + 1;\n }\n } else {\n pos = labelEnd + 1;\n }\n\n // covers label === '' and label === undefined\n // (collapsed reference link and shortcut reference link respectively)\n if (!label) { label = state.src.slice(labelStart, labelEnd); }\n\n ref = state.env.references[normalizeReference(label)];\n if (!ref) {\n state.pos = oldPos;\n return false;\n }\n href = ref.href;\n title = ref.title;\n }\n\n //\n // We found the end of the link, and know for a fact it's a valid link;\n // so all that's left to do is to call tokenizer.\n //\n if (!silent) {\n state.pos = labelStart;\n state.posMax = labelEnd;\n\n token = state.push('link_open', 'a', 1);\n token.attrs = attrs = [ [ 'href', href ] ];\n if (title) {\n attrs.push([ 'title', title ]);\n }\n\n state.md.inline.tokenize(state);\n\n token = state.push('link_close', 'a', -1);\n }\n\n state.pos = pos;\n state.posMax = max;\n return true;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_inline/link.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_inline/newline.js": -/*!**************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_inline/newline.js ***! - \**************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Proceess '\\n'\n\n\n\nvar isSpace = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").isSpace;\n\n\nmodule.exports = function newline(state, silent) {\n var pmax, max, pos = state.pos;\n\n if (state.src.charCodeAt(pos) !== 0x0A/* \\n */) { return false; }\n\n pmax = state.pending.length - 1;\n max = state.posMax;\n\n // ' \\n' -> hardbreak\n // Lookup in pending chars is bad practice! Don't copy to other rules!\n // Pending string is stored in concat mode, indexed lookups will cause\n // convertion to flat mode.\n if (!silent) {\n if (pmax >= 0 && state.pending.charCodeAt(pmax) === 0x20) {\n if (pmax >= 1 && state.pending.charCodeAt(pmax - 1) === 0x20) {\n state.pending = state.pending.replace(/ +$/, '');\n state.push('hardbreak', 'br', 0);\n } else {\n state.pending = state.pending.slice(0, -1);\n state.push('softbreak', 'br', 0);\n }\n\n } else {\n state.push('softbreak', 'br', 0);\n }\n }\n\n pos++;\n\n // skip heading spaces for next line\n while (pos < max && isSpace(state.src.charCodeAt(pos))) { pos++; }\n\n state.pos = pos;\n return true;\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_inline/newline.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_inline/state_inline.js": -/*!*******************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_inline/state_inline.js ***! - \*******************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Inline parser state\n\n\n\n\nvar Token = __webpack_require__(/*! ../token */ \"./node_modules/markdown-it/lib/token.js\");\nvar isWhiteSpace = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").isWhiteSpace;\nvar isPunctChar = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").isPunctChar;\nvar isMdAsciiPunct = __webpack_require__(/*! ../common/utils */ \"./node_modules/markdown-it/lib/common/utils.js\").isMdAsciiPunct;\n\n\nfunction StateInline(src, md, env, outTokens) {\n this.src = src;\n this.env = env;\n this.md = md;\n this.tokens = outTokens;\n this.tokens_meta = Array(outTokens.length);\n\n this.pos = 0;\n this.posMax = this.src.length;\n this.level = 0;\n this.pending = '';\n this.pendingLevel = 0;\n\n // Stores { start: end } pairs. Useful for backtrack\n // optimization of pairs parse (emphasis, strikes).\n this.cache = {};\n\n // List of emphasis-like delimiters for current tag\n this.delimiters = [];\n\n // Stack of delimiter lists for upper level tags\n this._prev_delimiters = [];\n\n // backtick length => last seen position\n this.backticks = {};\n this.backticksScanned = false;\n}\n\n\n// Flush pending text\n//\nStateInline.prototype.pushPending = function () {\n var token = new Token('text', '', 0);\n token.content = this.pending;\n token.level = this.pendingLevel;\n this.tokens.push(token);\n this.pending = '';\n return token;\n};\n\n\n// Push new token to \"stream\".\n// If pending text exists - flush it as text token\n//\nStateInline.prototype.push = function (type, tag, nesting) {\n if (this.pending) {\n this.pushPending();\n }\n\n var token = new Token(type, tag, nesting);\n var token_meta = null;\n\n if (nesting < 0) {\n // closing tag\n this.level--;\n this.delimiters = this._prev_delimiters.pop();\n }\n\n token.level = this.level;\n\n if (nesting > 0) {\n // opening tag\n this.level++;\n this._prev_delimiters.push(this.delimiters);\n this.delimiters = [];\n token_meta = { delimiters: this.delimiters };\n }\n\n this.pendingLevel = this.level;\n this.tokens.push(token);\n this.tokens_meta.push(token_meta);\n return token;\n};\n\n\n// Scan a sequence of emphasis-like markers, and determine whether\n// it can start an emphasis sequence or end an emphasis sequence.\n//\n// - start - position to scan from (it should point at a valid marker);\n// - canSplitWord - determine if these markers can be found inside a word\n//\nStateInline.prototype.scanDelims = function (start, canSplitWord) {\n var pos = start, lastChar, nextChar, count, can_open, can_close,\n isLastWhiteSpace, isLastPunctChar,\n isNextWhiteSpace, isNextPunctChar,\n left_flanking = true,\n right_flanking = true,\n max = this.posMax,\n marker = this.src.charCodeAt(start);\n\n // treat beginning of the line as a whitespace\n lastChar = start > 0 ? this.src.charCodeAt(start - 1) : 0x20;\n\n while (pos < max && this.src.charCodeAt(pos) === marker) { pos++; }\n\n count = pos - start;\n\n // treat end of the line as a whitespace\n nextChar = pos < max ? this.src.charCodeAt(pos) : 0x20;\n\n isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar));\n isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar));\n\n isLastWhiteSpace = isWhiteSpace(lastChar);\n isNextWhiteSpace = isWhiteSpace(nextChar);\n\n if (isNextWhiteSpace) {\n left_flanking = false;\n } else if (isNextPunctChar) {\n if (!(isLastWhiteSpace || isLastPunctChar)) {\n left_flanking = false;\n }\n }\n\n if (isLastWhiteSpace) {\n right_flanking = false;\n } else if (isLastPunctChar) {\n if (!(isNextWhiteSpace || isNextPunctChar)) {\n right_flanking = false;\n }\n }\n\n if (!canSplitWord) {\n can_open = left_flanking && (!right_flanking || isLastPunctChar);\n can_close = right_flanking && (!left_flanking || isNextPunctChar);\n } else {\n can_open = left_flanking;\n can_close = right_flanking;\n }\n\n return {\n can_open: can_open,\n can_close: can_close,\n length: count\n };\n};\n\n\n// re-export Token class to use in block rules\nStateInline.prototype.Token = Token;\n\n\nmodule.exports = StateInline;\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_inline/state_inline.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_inline/strikethrough.js": -/*!********************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_inline/strikethrough.js ***! - \********************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// ~~strike through~~\n//\n\n\n\n// Insert each marker as a separate text token, and add it to delimiter list\n//\nmodule.exports.tokenize = function strikethrough(state, silent) {\n var i, scanned, token, len, ch,\n start = state.pos,\n marker = state.src.charCodeAt(start);\n\n if (silent) { return false; }\n\n if (marker !== 0x7E/* ~ */) { return false; }\n\n scanned = state.scanDelims(state.pos, true);\n len = scanned.length;\n ch = String.fromCharCode(marker);\n\n if (len < 2) { return false; }\n\n if (len % 2) {\n token = state.push('text', '', 0);\n token.content = ch;\n len--;\n }\n\n for (i = 0; i < len; i += 2) {\n token = state.push('text', '', 0);\n token.content = ch + ch;\n\n state.delimiters.push({\n marker: marker,\n length: 0, // disable \"rule of 3\" length checks meant for emphasis\n jump: i,\n token: state.tokens.length - 1,\n end: -1,\n open: scanned.can_open,\n close: scanned.can_close\n });\n }\n\n state.pos += scanned.length;\n\n return true;\n};\n\n\nfunction postProcess(state, delimiters) {\n var i, j,\n startDelim,\n endDelim,\n token,\n loneMarkers = [],\n max = delimiters.length;\n\n for (i = 0; i < max; i++) {\n startDelim = delimiters[i];\n\n if (startDelim.marker !== 0x7E/* ~ */) {\n continue;\n }\n\n if (startDelim.end === -1) {\n continue;\n }\n\n endDelim = delimiters[startDelim.end];\n\n token = state.tokens[startDelim.token];\n token.type = 's_open';\n token.tag = 's';\n token.nesting = 1;\n token.markup = '~~';\n token.content = '';\n\n token = state.tokens[endDelim.token];\n token.type = 's_close';\n token.tag = 's';\n token.nesting = -1;\n token.markup = '~~';\n token.content = '';\n\n if (state.tokens[endDelim.token - 1].type === 'text' &&\n state.tokens[endDelim.token - 1].content === '~') {\n\n loneMarkers.push(endDelim.token - 1);\n }\n }\n\n // If a marker sequence has an odd number of characters, it's splitted\n // like this: `~~~~~` -> `~` + `~~` + `~~`, leaving one marker at the\n // start of the sequence.\n //\n // So, we have to move all those markers after subsequent s_close tags.\n //\n while (loneMarkers.length) {\n i = loneMarkers.pop();\n j = i + 1;\n\n while (j < state.tokens.length && state.tokens[j].type === 's_close') {\n j++;\n }\n\n j--;\n\n if (i !== j) {\n token = state.tokens[j];\n state.tokens[j] = state.tokens[i];\n state.tokens[i] = token;\n }\n }\n}\n\n\n// Walk through delimiter list and replace text tokens with tags\n//\nmodule.exports.postProcess = function strikethrough(state) {\n var curr,\n tokens_meta = state.tokens_meta,\n max = state.tokens_meta.length;\n\n postProcess(state, state.delimiters);\n\n for (curr = 0; curr < max; curr++) {\n if (tokens_meta[curr] && tokens_meta[curr].delimiters) {\n postProcess(state, tokens_meta[curr].delimiters);\n }\n }\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_inline/strikethrough.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_inline/text.js": -/*!***********************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_inline/text.js ***! - \***********************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Skip text characters for text token, place those to pending buffer\n// and increment current pos\n\n\n\n\n// Rule to skip pure text\n// '{}$%@~+=:' reserved for extentions\n\n// !, \", #, $, %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ?, @, [, \\, ], ^, _, `, {, |, }, or ~\n\n// !!!! Don't confuse with \"Markdown ASCII Punctuation\" chars\n// http://spec.commonmark.org/0.15/#ascii-punctuation-character\nfunction isTerminatorChar(ch) {\n switch (ch) {\n case 0x0A/* \\n */:\n case 0x21/* ! */:\n case 0x23/* # */:\n case 0x24/* $ */:\n case 0x25/* % */:\n case 0x26/* & */:\n case 0x2A/* * */:\n case 0x2B/* + */:\n case 0x2D/* - */:\n case 0x3A/* : */:\n case 0x3C/* < */:\n case 0x3D/* = */:\n case 0x3E/* > */:\n case 0x40/* @ */:\n case 0x5B/* [ */:\n case 0x5C/* \\ */:\n case 0x5D/* ] */:\n case 0x5E/* ^ */:\n case 0x5F/* _ */:\n case 0x60/* ` */:\n case 0x7B/* { */:\n case 0x7D/* } */:\n case 0x7E/* ~ */:\n return true;\n default:\n return false;\n }\n}\n\nmodule.exports = function text(state, silent) {\n var pos = state.pos;\n\n while (pos < state.posMax && !isTerminatorChar(state.src.charCodeAt(pos))) {\n pos++;\n }\n\n if (pos === state.pos) { return false; }\n\n if (!silent) { state.pending += state.src.slice(state.pos, pos); }\n\n state.pos = pos;\n\n return true;\n};\n\n// Alternative implementation, for memory.\n//\n// It costs 10% of performance, but allows extend terminators list, if place it\n// to `ParcerInline` property. Probably, will switch to it sometime, such\n// flexibility required.\n\n/*\nvar TERMINATOR_RE = /[\\n!#$%&*+\\-:<=>@[\\\\\\]^_`{}~]/;\n\nmodule.exports = function text(state, silent) {\n var pos = state.pos,\n idx = state.src.slice(pos).search(TERMINATOR_RE);\n\n // first char is terminator -> empty text\n if (idx === 0) { return false; }\n\n // no terminator -> text till end of string\n if (idx < 0) {\n if (!silent) { state.pending += state.src.slice(pos); }\n state.pos = state.src.length;\n return true;\n }\n\n if (!silent) { state.pending += state.src.slice(pos, pos + idx); }\n\n state.pos += idx;\n\n return true;\n};*/\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_inline/text.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/rules_inline/text_collapse.js": -/*!********************************************************************!*\ - !*** ./node_modules/markdown-it/lib/rules_inline/text_collapse.js ***! - \********************************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Clean up tokens after emphasis and strikethrough postprocessing:\n// merge adjacent text nodes into one and re-calculate all token levels\n//\n// This is necessary because initially emphasis delimiter markers (*, _, ~)\n// are treated as their own separate text tokens. Then emphasis rule either\n// leaves them as text (needed to merge with adjacent text) or turns them\n// into opening/closing tags (which messes up levels inside).\n//\n\n\n\nmodule.exports = function text_collapse(state) {\n var curr, last,\n level = 0,\n tokens = state.tokens,\n max = state.tokens.length;\n\n for (curr = last = 0; curr < max; curr++) {\n // re-calculate levels after emphasis/strikethrough turns some text nodes\n // into opening/closing tags\n if (tokens[curr].nesting < 0) level--; // closing tag\n tokens[curr].level = level;\n if (tokens[curr].nesting > 0) level++; // opening tag\n\n if (tokens[curr].type === 'text' &&\n curr + 1 < max &&\n tokens[curr + 1].type === 'text') {\n\n // collapse two adjacent text nodes\n tokens[curr + 1].content = tokens[curr].content + tokens[curr + 1].content;\n } else {\n if (curr !== last) { tokens[last] = tokens[curr]; }\n\n last++;\n }\n }\n\n if (curr !== last) {\n tokens.length = last;\n }\n};\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/rules_inline/text_collapse.js?"); - -/***/ }), - -/***/ "./node_modules/markdown-it/lib/token.js": -/*!***********************************************!*\ - !*** ./node_modules/markdown-it/lib/token.js ***! - \***********************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Token class\n\n\n\n\n/**\n * class Token\n **/\n\n/**\n * new Token(type, tag, nesting)\n *\n * Create new token and fill passed properties.\n **/\nfunction Token(type, tag, nesting) {\n /**\n * Token#type -> String\n *\n * Type of the token (string, e.g. \"paragraph_open\")\n **/\n this.type = type;\n\n /**\n * Token#tag -> String\n *\n * html tag name, e.g. \"p\"\n **/\n this.tag = tag;\n\n /**\n * Token#attrs -> Array\n *\n * Html attributes. Format: `[ [ name1, value1 ], [ name2, value2 ] ]`\n **/\n this.attrs = null;\n\n /**\n * Token#map -> Array\n *\n * Source map info. Format: `[ line_begin, line_end ]`\n **/\n this.map = null;\n\n /**\n * Token#nesting -> Number\n *\n * Level change (number in {-1, 0, 1} set), where:\n *\n * - `1` means the tag is opening\n * - `0` means the tag is self-closing\n * - `-1` means the tag is closing\n **/\n this.nesting = nesting;\n\n /**\n * Token#level -> Number\n *\n * nesting level, the same as `state.level`\n **/\n this.level = 0;\n\n /**\n * Token#children -> Array\n *\n * An array of child nodes (inline and img tokens)\n **/\n this.children = null;\n\n /**\n * Token#content -> String\n *\n * In a case of self-closing tag (code, html, fence, etc.),\n * it has contents of this tag.\n **/\n this.content = '';\n\n /**\n * Token#markup -> String\n *\n * '*' or '_' for emphasis, fence string for fence, etc.\n **/\n this.markup = '';\n\n /**\n * Token#info -> String\n *\n * fence infostring\n **/\n this.info = '';\n\n /**\n * Token#meta -> Object\n *\n * A place for plugins to store an arbitrary data\n **/\n this.meta = null;\n\n /**\n * Token#block -> Boolean\n *\n * True for block-level tokens, false for inline tokens.\n * Used in renderer to calculate line breaks\n **/\n this.block = false;\n\n /**\n * Token#hidden -> Boolean\n *\n * If it's true, ignore this element when rendering. Used for tight lists\n * to hide paragraphs.\n **/\n this.hidden = false;\n}\n\n\n/**\n * Token.attrIndex(name) -> Number\n *\n * Search attribute index by name.\n **/\nToken.prototype.attrIndex = function attrIndex(name) {\n var attrs, i, len;\n\n if (!this.attrs) { return -1; }\n\n attrs = this.attrs;\n\n for (i = 0, len = attrs.length; i < len; i++) {\n if (attrs[i][0] === name) { return i; }\n }\n return -1;\n};\n\n\n/**\n * Token.attrPush(attrData)\n *\n * Add `[ name, value ]` attribute to list. Init attrs if necessary\n **/\nToken.prototype.attrPush = function attrPush(attrData) {\n if (this.attrs) {\n this.attrs.push(attrData);\n } else {\n this.attrs = [ attrData ];\n }\n};\n\n\n/**\n * Token.attrSet(name, value)\n *\n * Set `name` attribute to `value`. Override old value if exists.\n **/\nToken.prototype.attrSet = function attrSet(name, value) {\n var idx = this.attrIndex(name),\n attrData = [ name, value ];\n\n if (idx < 0) {\n this.attrPush(attrData);\n } else {\n this.attrs[idx] = attrData;\n }\n};\n\n\n/**\n * Token.attrGet(name)\n *\n * Get the value of attribute `name`, or null if it does not exist.\n **/\nToken.prototype.attrGet = function attrGet(name) {\n var idx = this.attrIndex(name), value = null;\n if (idx >= 0) {\n value = this.attrs[idx][1];\n }\n return value;\n};\n\n\n/**\n * Token.attrJoin(name, value)\n *\n * Join value to existing attribute via space. Or create new attribute if not\n * exists. Useful to operate with token classes.\n **/\nToken.prototype.attrJoin = function attrJoin(name, value) {\n var idx = this.attrIndex(name);\n\n if (idx < 0) {\n this.attrPush([ name, value ]);\n } else {\n this.attrs[idx][1] = this.attrs[idx][1] + ' ' + value;\n }\n};\n\n\nmodule.exports = Token;\n\n\n//# sourceURL=webpack:///./node_modules/markdown-it/lib/token.js?"); - -/***/ }), - -/***/ "./node_modules/mdurl/decode.js": -/*!**************************************!*\ - !*** ./node_modules/mdurl/decode.js ***! - \**************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("\n\n\n\n/* eslint-disable no-bitwise */\n\nvar decodeCache = {};\n\nfunction getDecodeCache(exclude) {\n var i, ch, cache = decodeCache[exclude];\n if (cache) { return cache; }\n\n cache = decodeCache[exclude] = [];\n\n for (i = 0; i < 128; i++) {\n ch = String.fromCharCode(i);\n cache.push(ch);\n }\n\n for (i = 0; i < exclude.length; i++) {\n ch = exclude.charCodeAt(i);\n cache[ch] = '%' + ('0' + ch.toString(16).toUpperCase()).slice(-2);\n }\n\n return cache;\n}\n\n\n// Decode percent-encoded string.\n//\nfunction decode(string, exclude) {\n var cache;\n\n if (typeof exclude !== 'string') {\n exclude = decode.defaultChars;\n }\n\n cache = getDecodeCache(exclude);\n\n return string.replace(/(%[a-f0-9]{2})+/gi, function(seq) {\n var i, l, b1, b2, b3, b4, chr,\n result = '';\n\n for (i = 0, l = seq.length; i < l; i += 3) {\n b1 = parseInt(seq.slice(i + 1, i + 3), 16);\n\n if (b1 < 0x80) {\n result += cache[b1];\n continue;\n }\n\n if ((b1 & 0xE0) === 0xC0 && (i + 3 < l)) {\n // 110xxxxx 10xxxxxx\n b2 = parseInt(seq.slice(i + 4, i + 6), 16);\n\n if ((b2 & 0xC0) === 0x80) {\n chr = ((b1 << 6) & 0x7C0) | (b2 & 0x3F);\n\n if (chr < 0x80) {\n result += '\\ufffd\\ufffd';\n } else {\n result += String.fromCharCode(chr);\n }\n\n i += 3;\n continue;\n }\n }\n\n if ((b1 & 0xF0) === 0xE0 && (i + 6 < l)) {\n // 1110xxxx 10xxxxxx 10xxxxxx\n b2 = parseInt(seq.slice(i + 4, i + 6), 16);\n b3 = parseInt(seq.slice(i + 7, i + 9), 16);\n\n if ((b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) {\n chr = ((b1 << 12) & 0xF000) | ((b2 << 6) & 0xFC0) | (b3 & 0x3F);\n\n if (chr < 0x800 || (chr >= 0xD800 && chr <= 0xDFFF)) {\n result += '\\ufffd\\ufffd\\ufffd';\n } else {\n result += String.fromCharCode(chr);\n }\n\n i += 6;\n continue;\n }\n }\n\n if ((b1 & 0xF8) === 0xF0 && (i + 9 < l)) {\n // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx\n b2 = parseInt(seq.slice(i + 4, i + 6), 16);\n b3 = parseInt(seq.slice(i + 7, i + 9), 16);\n b4 = parseInt(seq.slice(i + 10, i + 12), 16);\n\n if ((b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80 && (b4 & 0xC0) === 0x80) {\n chr = ((b1 << 18) & 0x1C0000) | ((b2 << 12) & 0x3F000) | ((b3 << 6) & 0xFC0) | (b4 & 0x3F);\n\n if (chr < 0x10000 || chr > 0x10FFFF) {\n result += '\\ufffd\\ufffd\\ufffd\\ufffd';\n } else {\n chr -= 0x10000;\n result += String.fromCharCode(0xD800 + (chr >> 10), 0xDC00 + (chr & 0x3FF));\n }\n\n i += 9;\n continue;\n }\n }\n\n result += '\\ufffd';\n }\n\n return result;\n });\n}\n\n\ndecode.defaultChars = ';/?:@&=+$,#';\ndecode.componentChars = '';\n\n\nmodule.exports = decode;\n\n\n//# sourceURL=webpack:///./node_modules/mdurl/decode.js?"); - -/***/ }), - -/***/ "./node_modules/mdurl/encode.js": -/*!**************************************!*\ - !*** ./node_modules/mdurl/encode.js ***! - \**************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("\n\n\n\nvar encodeCache = {};\n\n\n// Create a lookup array where anything but characters in `chars` string\n// and alphanumeric chars is percent-encoded.\n//\nfunction getEncodeCache(exclude) {\n var i, ch, cache = encodeCache[exclude];\n if (cache) { return cache; }\n\n cache = encodeCache[exclude] = [];\n\n for (i = 0; i < 128; i++) {\n ch = String.fromCharCode(i);\n\n if (/^[0-9a-z]$/i.test(ch)) {\n // always allow unencoded alphanumeric characters\n cache.push(ch);\n } else {\n cache.push('%' + ('0' + i.toString(16).toUpperCase()).slice(-2));\n }\n }\n\n for (i = 0; i < exclude.length; i++) {\n cache[exclude.charCodeAt(i)] = exclude[i];\n }\n\n return cache;\n}\n\n\n// Encode unsafe characters with percent-encoding, skipping already\n// encoded sequences.\n//\n// - string - string to encode\n// - exclude - list of characters to ignore (in addition to a-zA-Z0-9)\n// - keepEscaped - don't encode '%' in a correct escape sequence (default: true)\n//\nfunction encode(string, exclude, keepEscaped) {\n var i, l, code, nextCode, cache,\n result = '';\n\n if (typeof exclude !== 'string') {\n // encode(string, keepEscaped)\n keepEscaped = exclude;\n exclude = encode.defaultChars;\n }\n\n if (typeof keepEscaped === 'undefined') {\n keepEscaped = true;\n }\n\n cache = getEncodeCache(exclude);\n\n for (i = 0, l = string.length; i < l; i++) {\n code = string.charCodeAt(i);\n\n if (keepEscaped && code === 0x25 /* % */ && i + 2 < l) {\n if (/^[0-9a-f]{2}$/i.test(string.slice(i + 1, i + 3))) {\n result += string.slice(i, i + 3);\n i += 2;\n continue;\n }\n }\n\n if (code < 128) {\n result += cache[code];\n continue;\n }\n\n if (code >= 0xD800 && code <= 0xDFFF) {\n if (code >= 0xD800 && code <= 0xDBFF && i + 1 < l) {\n nextCode = string.charCodeAt(i + 1);\n if (nextCode >= 0xDC00 && nextCode <= 0xDFFF) {\n result += encodeURIComponent(string[i] + string[i + 1]);\n i++;\n continue;\n }\n }\n result += '%EF%BF%BD';\n continue;\n }\n\n result += encodeURIComponent(string[i]);\n }\n\n return result;\n}\n\nencode.defaultChars = \";/?:@&=+$,-_.!~*'()#\";\nencode.componentChars = \"-_.!~*'()\";\n\n\nmodule.exports = encode;\n\n\n//# sourceURL=webpack:///./node_modules/mdurl/encode.js?"); - -/***/ }), - -/***/ "./node_modules/mdurl/format.js": -/*!**************************************!*\ - !*** ./node_modules/mdurl/format.js ***! - \**************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("\n\n\n\nmodule.exports = function format(url) {\n var result = '';\n\n result += url.protocol || '';\n result += url.slashes ? '//' : '';\n result += url.auth ? url.auth + '@' : '';\n\n if (url.hostname && url.hostname.indexOf(':') !== -1) {\n // ipv6 address\n result += '[' + url.hostname + ']';\n } else {\n result += url.hostname || '';\n }\n\n result += url.port ? ':' + url.port : '';\n result += url.pathname || '';\n result += url.search || '';\n result += url.hash || '';\n\n return result;\n};\n\n\n//# sourceURL=webpack:///./node_modules/mdurl/format.js?"); - -/***/ }), - -/***/ "./node_modules/mdurl/index.js": -/*!*************************************!*\ - !*** ./node_modules/mdurl/index.js ***! - \*************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("\n\n\nmodule.exports.encode = __webpack_require__(/*! ./encode */ \"./node_modules/mdurl/encode.js\");\nmodule.exports.decode = __webpack_require__(/*! ./decode */ \"./node_modules/mdurl/decode.js\");\nmodule.exports.format = __webpack_require__(/*! ./format */ \"./node_modules/mdurl/format.js\");\nmodule.exports.parse = __webpack_require__(/*! ./parse */ \"./node_modules/mdurl/parse.js\");\n\n\n//# sourceURL=webpack:///./node_modules/mdurl/index.js?"); - -/***/ }), - -/***/ "./node_modules/mdurl/parse.js": -/*!*************************************!*\ - !*** ./node_modules/mdurl/parse.js ***! - \*************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n\n//\n// Changes from joyent/node:\n//\n// 1. No leading slash in paths,\n// e.g. in `url.parse('http://foo?bar')` pathname is ``, not `/`\n//\n// 2. Backslashes are not replaced with slashes,\n// so `http:\\\\example.org\\` is treated like a relative path\n//\n// 3. Trailing colon is treated like a part of the path,\n// i.e. in `http://example.org:foo` pathname is `:foo`\n//\n// 4. Nothing is URL-encoded in the resulting object,\n// (in joyent/node some chars in auth and paths are encoded)\n//\n// 5. `url.parse()` does not have `parseQueryString` argument\n//\n// 6. Removed extraneous result properties: `host`, `path`, `query`, etc.,\n// which can be constructed using other parts of the url.\n//\n\n\nfunction Url() {\n this.protocol = null;\n this.slashes = null;\n this.auth = null;\n this.port = null;\n this.hostname = null;\n this.hash = null;\n this.search = null;\n this.pathname = null;\n}\n\n// Reference: RFC 3986, RFC 1808, RFC 2396\n\n// define these here so at least they only have to be\n// compiled once on the first module load.\nvar protocolPattern = /^([a-z0-9.+-]+:)/i,\n portPattern = /:[0-9]*$/,\n\n // Special case for a simple path URL\n simplePathPattern = /^(\\/\\/?(?!\\/)[^\\?\\s]*)(\\?[^\\s]*)?$/,\n\n // RFC 2396: characters reserved for delimiting URLs.\n // We actually just auto-escape these.\n delims = [ '<', '>', '\"', '`', ' ', '\\r', '\\n', '\\t' ],\n\n // RFC 2396: characters not allowed for various reasons.\n unwise = [ '{', '}', '|', '\\\\', '^', '`' ].concat(delims),\n\n // Allowed by RFCs, but cause of XSS attacks. Always escape these.\n autoEscape = [ '\\'' ].concat(unwise),\n // Characters that are never ever allowed in a hostname.\n // Note that any invalid chars are also handled, but these\n // are the ones that are *expected* to be seen, so we fast-path\n // them.\n nonHostChars = [ '%', '/', '?', ';', '#' ].concat(autoEscape),\n hostEndingChars = [ '/', '?', '#' ],\n hostnameMaxLen = 255,\n hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/,\n hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/,\n // protocols that can allow \"unsafe\" and \"unwise\" chars.\n /* eslint-disable no-script-url */\n // protocols that never have a hostname.\n hostlessProtocol = {\n 'javascript': true,\n 'javascript:': true\n },\n // protocols that always contain a // bit.\n slashedProtocol = {\n 'http': true,\n 'https': true,\n 'ftp': true,\n 'gopher': true,\n 'file': true,\n 'http:': true,\n 'https:': true,\n 'ftp:': true,\n 'gopher:': true,\n 'file:': true\n };\n /* eslint-enable no-script-url */\n\nfunction urlParse(url, slashesDenoteHost) {\n if (url && url instanceof Url) { return url; }\n\n var u = new Url();\n u.parse(url, slashesDenoteHost);\n return u;\n}\n\nUrl.prototype.parse = function(url, slashesDenoteHost) {\n var i, l, lowerProto, hec, slashes,\n rest = url;\n\n // trim before proceeding.\n // This is to support parse stuff like \" http://foo.com \\n\"\n rest = rest.trim();\n\n if (!slashesDenoteHost && url.split('#').length === 1) {\n // Try fast path regexp\n var simplePath = simplePathPattern.exec(rest);\n if (simplePath) {\n this.pathname = simplePath[1];\n if (simplePath[2]) {\n this.search = simplePath[2];\n }\n return this;\n }\n }\n\n var proto = protocolPattern.exec(rest);\n if (proto) {\n proto = proto[0];\n lowerProto = proto.toLowerCase();\n this.protocol = proto;\n rest = rest.substr(proto.length);\n }\n\n // figure out if it's got a host\n // user@server is *always* interpreted as a hostname, and url\n // resolution will treat //foo/bar as host=foo,path=bar because that's\n // how the browser resolves relative URLs.\n if (slashesDenoteHost || proto || rest.match(/^\\/\\/[^@\\/]+@[^@\\/]+/)) {\n slashes = rest.substr(0, 2) === '//';\n if (slashes && !(proto && hostlessProtocol[proto])) {\n rest = rest.substr(2);\n this.slashes = true;\n }\n }\n\n if (!hostlessProtocol[proto] &&\n (slashes || (proto && !slashedProtocol[proto]))) {\n\n // there's a hostname.\n // the first instance of /, ?, ;, or # ends the host.\n //\n // If there is an @ in the hostname, then non-host chars *are* allowed\n // to the left of the last @ sign, unless some host-ending character\n // comes *before* the @-sign.\n // URLs are obnoxious.\n //\n // ex:\n // http://a@b@c/ => user:a@b host:c\n // http://a@b?@c => user:a host:c path:/?@c\n\n // v0.12 TODO(isaacs): This is not quite how Chrome does things.\n // Review our test case against browsers more comprehensively.\n\n // find the first instance of any hostEndingChars\n var hostEnd = -1;\n for (i = 0; i < hostEndingChars.length; i++) {\n hec = rest.indexOf(hostEndingChars[i]);\n if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {\n hostEnd = hec;\n }\n }\n\n // at this point, either we have an explicit point where the\n // auth portion cannot go past, or the last @ char is the decider.\n var auth, atSign;\n if (hostEnd === -1) {\n // atSign can be anywhere.\n atSign = rest.lastIndexOf('@');\n } else {\n // atSign must be in auth portion.\n // http://a@b/c@d => host:b auth:a path:/c@d\n atSign = rest.lastIndexOf('@', hostEnd);\n }\n\n // Now we have a portion which is definitely the auth.\n // Pull that off.\n if (atSign !== -1) {\n auth = rest.slice(0, atSign);\n rest = rest.slice(atSign + 1);\n this.auth = auth;\n }\n\n // the host is the remaining to the left of the first non-host char\n hostEnd = -1;\n for (i = 0; i < nonHostChars.length; i++) {\n hec = rest.indexOf(nonHostChars[i]);\n if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {\n hostEnd = hec;\n }\n }\n // if we still have not hit it, then the entire thing is a host.\n if (hostEnd === -1) {\n hostEnd = rest.length;\n }\n\n if (rest[hostEnd - 1] === ':') { hostEnd--; }\n var host = rest.slice(0, hostEnd);\n rest = rest.slice(hostEnd);\n\n // pull out port.\n this.parseHost(host);\n\n // we've indicated that there is a hostname,\n // so even if it's empty, it has to be present.\n this.hostname = this.hostname || '';\n\n // if hostname begins with [ and ends with ]\n // assume that it's an IPv6 address.\n var ipv6Hostname = this.hostname[0] === '[' &&\n this.hostname[this.hostname.length - 1] === ']';\n\n // validate a little.\n if (!ipv6Hostname) {\n var hostparts = this.hostname.split(/\\./);\n for (i = 0, l = hostparts.length; i < l; i++) {\n var part = hostparts[i];\n if (!part) { continue; }\n if (!part.match(hostnamePartPattern)) {\n var newpart = '';\n for (var j = 0, k = part.length; j < k; j++) {\n if (part.charCodeAt(j) > 127) {\n // we replace non-ASCII char with a temporary placeholder\n // we need this to make sure size of hostname is not\n // broken by replacing non-ASCII by nothing\n newpart += 'x';\n } else {\n newpart += part[j];\n }\n }\n // we test again with ASCII char only\n if (!newpart.match(hostnamePartPattern)) {\n var validParts = hostparts.slice(0, i);\n var notHost = hostparts.slice(i + 1);\n var bit = part.match(hostnamePartStart);\n if (bit) {\n validParts.push(bit[1]);\n notHost.unshift(bit[2]);\n }\n if (notHost.length) {\n rest = notHost.join('.') + rest;\n }\n this.hostname = validParts.join('.');\n break;\n }\n }\n }\n }\n\n if (this.hostname.length > hostnameMaxLen) {\n this.hostname = '';\n }\n\n // strip [ and ] from the hostname\n // the host field still retains them, though\n if (ipv6Hostname) {\n this.hostname = this.hostname.substr(1, this.hostname.length - 2);\n }\n }\n\n // chop off from the tail first.\n var hash = rest.indexOf('#');\n if (hash !== -1) {\n // got a fragment string.\n this.hash = rest.substr(hash);\n rest = rest.slice(0, hash);\n }\n var qm = rest.indexOf('?');\n if (qm !== -1) {\n this.search = rest.substr(qm);\n rest = rest.slice(0, qm);\n }\n if (rest) { this.pathname = rest; }\n if (slashedProtocol[lowerProto] &&\n this.hostname && !this.pathname) {\n this.pathname = '';\n }\n\n return this;\n};\n\nUrl.prototype.parseHost = function(host) {\n var port = portPattern.exec(host);\n if (port) {\n port = port[0];\n if (port !== ':') {\n this.port = port.substr(1);\n }\n host = host.substr(0, host.length - port.length);\n }\n if (host) { this.hostname = host; }\n};\n\nmodule.exports = urlParse;\n\n\n//# sourceURL=webpack:///./node_modules/mdurl/parse.js?"); - -/***/ }), - -/***/ "./node_modules/uc.micro/categories/Cc/regex.js": -/*!******************************************************!*\ - !*** ./node_modules/uc.micro/categories/Cc/regex.js ***! - \******************************************************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -eval("module.exports=/[\\0-\\x1F\\x7F-\\x9F]/\n\n//# sourceURL=webpack:///./node_modules/uc.micro/categories/Cc/regex.js?"); - -/***/ }), - -/***/ "./node_modules/uc.micro/categories/Cf/regex.js": -/*!******************************************************!*\ - !*** ./node_modules/uc.micro/categories/Cf/regex.js ***! - \******************************************************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -eval("module.exports=/[\\xAD\\u0600-\\u0605\\u061C\\u06DD\\u070F\\u08E2\\u180E\\u200B-\\u200F\\u202A-\\u202E\\u2060-\\u2064\\u2066-\\u206F\\uFEFF\\uFFF9-\\uFFFB]|\\uD804\\uDCBD|\\uD82F[\\uDCA0-\\uDCA3]|\\uD834[\\uDD73-\\uDD7A]|\\uDB40[\\uDC01\\uDC20-\\uDC7F]/\n\n//# sourceURL=webpack:///./node_modules/uc.micro/categories/Cf/regex.js?"); - -/***/ }), - -/***/ "./node_modules/uc.micro/categories/P/regex.js": -/*!*****************************************************!*\ - !*** ./node_modules/uc.micro/categories/P/regex.js ***! - \*****************************************************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -eval("module.exports=/[!-#%-\\*,-/:;\\?@\\[-\\]_\\{\\}\\xA1\\xA7\\xAB\\xB6\\xB7\\xBB\\xBF\\u037E\\u0387\\u055A-\\u055F\\u0589\\u058A\\u05BE\\u05C0\\u05C3\\u05C6\\u05F3\\u05F4\\u0609\\u060A\\u060C\\u060D\\u061B\\u061E\\u061F\\u066A-\\u066D\\u06D4\\u0700-\\u070D\\u07F7-\\u07F9\\u0830-\\u083E\\u085E\\u0964\\u0965\\u0970\\u09FD\\u0AF0\\u0DF4\\u0E4F\\u0E5A\\u0E5B\\u0F04-\\u0F12\\u0F14\\u0F3A-\\u0F3D\\u0F85\\u0FD0-\\u0FD4\\u0FD9\\u0FDA\\u104A-\\u104F\\u10FB\\u1360-\\u1368\\u1400\\u166D\\u166E\\u169B\\u169C\\u16EB-\\u16ED\\u1735\\u1736\\u17D4-\\u17D6\\u17D8-\\u17DA\\u1800-\\u180A\\u1944\\u1945\\u1A1E\\u1A1F\\u1AA0-\\u1AA6\\u1AA8-\\u1AAD\\u1B5A-\\u1B60\\u1BFC-\\u1BFF\\u1C3B-\\u1C3F\\u1C7E\\u1C7F\\u1CC0-\\u1CC7\\u1CD3\\u2010-\\u2027\\u2030-\\u2043\\u2045-\\u2051\\u2053-\\u205E\\u207D\\u207E\\u208D\\u208E\\u2308-\\u230B\\u2329\\u232A\\u2768-\\u2775\\u27C5\\u27C6\\u27E6-\\u27EF\\u2983-\\u2998\\u29D8-\\u29DB\\u29FC\\u29FD\\u2CF9-\\u2CFC\\u2CFE\\u2CFF\\u2D70\\u2E00-\\u2E2E\\u2E30-\\u2E49\\u3001-\\u3003\\u3008-\\u3011\\u3014-\\u301F\\u3030\\u303D\\u30A0\\u30FB\\uA4FE\\uA4FF\\uA60D-\\uA60F\\uA673\\uA67E\\uA6F2-\\uA6F7\\uA874-\\uA877\\uA8CE\\uA8CF\\uA8F8-\\uA8FA\\uA8FC\\uA92E\\uA92F\\uA95F\\uA9C1-\\uA9CD\\uA9DE\\uA9DF\\uAA5C-\\uAA5F\\uAADE\\uAADF\\uAAF0\\uAAF1\\uABEB\\uFD3E\\uFD3F\\uFE10-\\uFE19\\uFE30-\\uFE52\\uFE54-\\uFE61\\uFE63\\uFE68\\uFE6A\\uFE6B\\uFF01-\\uFF03\\uFF05-\\uFF0A\\uFF0C-\\uFF0F\\uFF1A\\uFF1B\\uFF1F\\uFF20\\uFF3B-\\uFF3D\\uFF3F\\uFF5B\\uFF5D\\uFF5F-\\uFF65]|\\uD800[\\uDD00-\\uDD02\\uDF9F\\uDFD0]|\\uD801\\uDD6F|\\uD802[\\uDC57\\uDD1F\\uDD3F\\uDE50-\\uDE58\\uDE7F\\uDEF0-\\uDEF6\\uDF39-\\uDF3F\\uDF99-\\uDF9C]|\\uD804[\\uDC47-\\uDC4D\\uDCBB\\uDCBC\\uDCBE-\\uDCC1\\uDD40-\\uDD43\\uDD74\\uDD75\\uDDC5-\\uDDC9\\uDDCD\\uDDDB\\uDDDD-\\uDDDF\\uDE38-\\uDE3D\\uDEA9]|\\uD805[\\uDC4B-\\uDC4F\\uDC5B\\uDC5D\\uDCC6\\uDDC1-\\uDDD7\\uDE41-\\uDE43\\uDE60-\\uDE6C\\uDF3C-\\uDF3E]|\\uD806[\\uDE3F-\\uDE46\\uDE9A-\\uDE9C\\uDE9E-\\uDEA2]|\\uD807[\\uDC41-\\uDC45\\uDC70\\uDC71]|\\uD809[\\uDC70-\\uDC74]|\\uD81A[\\uDE6E\\uDE6F\\uDEF5\\uDF37-\\uDF3B\\uDF44]|\\uD82F\\uDC9F|\\uD836[\\uDE87-\\uDE8B]|\\uD83A[\\uDD5E\\uDD5F]/\n\n//# sourceURL=webpack:///./node_modules/uc.micro/categories/P/regex.js?"); - -/***/ }), - -/***/ "./node_modules/uc.micro/categories/Z/regex.js": -/*!*****************************************************!*\ - !*** ./node_modules/uc.micro/categories/Z/regex.js ***! - \*****************************************************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -eval("module.exports=/[ \\xA0\\u1680\\u2000-\\u200A\\u202F\\u205F\\u3000]/\n\n//# sourceURL=webpack:///./node_modules/uc.micro/categories/Z/regex.js?"); - -/***/ }), - -/***/ "./node_modules/uc.micro/index.js": -/*!****************************************!*\ - !*** ./node_modules/uc.micro/index.js ***! - \****************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("\n\nexports.Any = __webpack_require__(/*! ./properties/Any/regex */ \"./node_modules/uc.micro/properties/Any/regex.js\");\nexports.Cc = __webpack_require__(/*! ./categories/Cc/regex */ \"./node_modules/uc.micro/categories/Cc/regex.js\");\nexports.Cf = __webpack_require__(/*! ./categories/Cf/regex */ \"./node_modules/uc.micro/categories/Cf/regex.js\");\nexports.P = __webpack_require__(/*! ./categories/P/regex */ \"./node_modules/uc.micro/categories/P/regex.js\");\nexports.Z = __webpack_require__(/*! ./categories/Z/regex */ \"./node_modules/uc.micro/categories/Z/regex.js\");\n\n\n//# sourceURL=webpack:///./node_modules/uc.micro/index.js?"); - -/***/ }), - -/***/ "./node_modules/uc.micro/properties/Any/regex.js": -/*!*******************************************************!*\ - !*** ./node_modules/uc.micro/properties/Any/regex.js ***! - \*******************************************************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -eval("module.exports=/[\\0-\\uD7FF\\uE000-\\uFFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]/\n\n//# sourceURL=webpack:///./node_modules/uc.micro/properties/Any/regex.js?"); - -/***/ }), - -/***/ "./notebook/index.ts": -/*!***************************!*\ - !*** ./notebook/index.ts ***! - \***************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("\n/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst MarkdownIt = __webpack_require__(/*! markdown-it */ \"./node_modules/markdown-it/index.js\");\n(function () {\n const markdownIt = new MarkdownIt();\n globalThis.extendMarkdownIt = ((f) => {\n f(markdownIt);\n });\n const notebook = acquireNotebookRendererApi('notebookCoreTestRenderer');\n notebook.onDidCreateMarkdown(({ element, content }) => {\n console.log('did create markdown cell');\n const rendered = markdownIt.render(content);\n element.innerHTML = rendered;\n });\n console.log('markdown-it');\n}());\n\n\n//# sourceURL=webpack:///./notebook/index.ts?"); - -/***/ }) - -/******/ }); \ No newline at end of file +!function(e){var t={};function r(n){if(t[n])return t[n].exports;var s=t[n]={i:n,l:!1,exports:{}};return e[n].call(s.exports,s,s.exports,r),s.l=!0,s.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var s in e)r.d(n,s,function(t){return e[t]}.bind(null,s));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=9)}([function(e,t,r){"use strict";var n=Object.prototype.hasOwnProperty;function s(e,t){return n.call(e,t)}function o(e){return!(e>=55296&&e<=57343)&&(!(e>=64976&&e<=65007)&&(65535!=(65535&e)&&65534!=(65535&e)&&(!(e>=0&&e<=8)&&(11!==e&&(!(e>=14&&e<=31)&&(!(e>=127&&e<=159)&&!(e>1114111)))))))}function i(e){if(e>65535){var t=55296+((e-=65536)>>10),r=56320+(1023&e);return String.fromCharCode(t,r)}return String.fromCharCode(e)}var a=/\\([!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~])/g,u=new RegExp(a.source+"|"+/&([a-z#][a-z0-9]{1,31});/gi.source,"gi"),c=/^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i,l=r(3);var p=/[&<>"]/,h=/[&<>"]/g,f={"&":"&","<":"<",">":">",'"':"""};function d(e){return f[e]}var m=/[.?*+^$[\]\\(){}|-]/g;var g=r(4);t.lib={},t.lib.mdurl=r(5),t.lib.ucmicro=r(17),t.assign=function(e){var t=Array.prototype.slice.call(arguments,1);return t.forEach((function(t){if(t){if("object"!=typeof t)throw new TypeError(t+"must be object");Object.keys(t).forEach((function(r){e[r]=t[r]}))}})),e},t.isString=function(e){return"[object String]"===function(e){return Object.prototype.toString.call(e)}(e)},t.has=s,t.unescapeMd=function(e){return e.indexOf("\\")<0?e:e.replace(a,"$1")},t.unescapeAll=function(e){return e.indexOf("\\")<0&&e.indexOf("&")<0?e:e.replace(u,(function(e,t,r){return t||function(e,t){var r=0;return s(l,t)?l[t]:35===t.charCodeAt(0)&&c.test(t)&&o(r="x"===t[1].toLowerCase()?parseInt(t.slice(2),16):parseInt(t.slice(1),10))?i(r):e}(e,r)}))},t.isValidEntityCode=o,t.fromCodePoint=i,t.escapeHtml=function(e){return p.test(e)?e.replace(h,d):e},t.arrayReplaceAt=function(e,t,r){return[].concat(e.slice(0,t),r,e.slice(t+1))},t.isSpace=function(e){switch(e){case 9:case 32:return!0}return!1},t.isWhiteSpace=function(e){if(e>=8192&&e<=8202)return!0;switch(e){case 9:case 10:case 11:case 12:case 13:case 32:case 160:case 5760:case 8239:case 8287:case 12288:return!0}return!1},t.isMdAsciiPunct=function(e){switch(e){case 33:case 34:case 35:case 36:case 37:case 38:case 39:case 40:case 41:case 42:case 43:case 44:case 45:case 46:case 47:case 58:case 59:case 60:case 61:case 62:case 63:case 64:case 91:case 92:case 93:case 94:case 95:case 96:case 123:case 124:case 125:case 126:return!0;default:return!1}},t.isPunctChar=function(e){return g.test(e)},t.escapeRE=function(e){return e.replace(m,"\\$&")},t.normalizeReference=function(e){return e=e.trim().replace(/\s+/g," "),"Ṿ"==="ẞ".toLowerCase()&&(e=e.replace(/ẞ/g,"ß")),e.toLowerCase().toUpperCase()}},function(e,t,r){"use strict";function n(){this.__rules__=[],this.__cache__=null}n.prototype.__find__=function(e){for(var t=0;t=0&&(r=this.attrs[t][1]),r},n.prototype.attrJoin=function(e,t){var r=this.attrIndex(e);r<0?this.attrPush([e,t]):this.attrs[r][1]=this.attrs[r][1]+" "+t},e.exports=n},function(e,t,r){"use strict";e.exports=r(12)},function(e,t){e.exports=/[!-#%-\*,-/:;\?@\[-\]_\{\}\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u09FD\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E49\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC9\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDC4B-\uDC4F\uDC5B\uDC5D\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDE60-\uDE6C\uDF3C-\uDF3E]|\uD806[\uDE3F-\uDE46\uDE9A-\uDE9C\uDE9E-\uDEA2]|\uD807[\uDC41-\uDC45\uDC70\uDC71]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]|\uD83A[\uDD5E\uDD5F]/},function(e,t,r){"use strict";e.exports.encode=r(13),e.exports.decode=r(14),e.exports.format=r(15),e.exports.parse=r(16)},function(e,t,r){"use strict";var n="<[A-Za-z][A-Za-z0-9\\-]*(?:\\s+[a-zA-Z_:][a-zA-Z0-9:._-]*(?:\\s*=\\s*(?:[^\"'=<>`\\x00-\\x20]+|'[^']*'|\"[^\"]*\"))?)*\\s*\\/?>",s="<\\/[A-Za-z][A-Za-z0-9\\-]*\\s*>",o=new RegExp("^(?:"+n+"|"+s+"|\x3c!----\x3e|\x3c!--(?:-?[^>-])(?:-?[^-])*--\x3e|<[?][\\s\\S]*?[?]>|]*>|)"),i=new RegExp("^(?:"+n+"|"+s+")");e.exports.HTML_TAG_RE=o,e.exports.HTML_OPEN_CLOSE_TAG_RE=i},function(e,t,r){"use strict";function n(e,t){var r,n,s,o,i,a=[],u=t.length;for(r=0;r=0;r--)95!==(n=t[r]).marker&&42!==n.marker||-1!==n.end&&(s=t[n.end],a=r>0&&t[r-1].end===n.end+1&&t[r-1].token===n.token-1&&t[n.end+1].token===s.token+1&&t[r-1].marker===n.marker,i=String.fromCharCode(n.marker),(o=e.tokens[n.token]).type=a?"strong_open":"em_open",o.tag=a?"strong":"em",o.nesting=1,o.markup=a?i+i:i,o.content="",(o=e.tokens[s.token]).type=a?"strong_close":"em_close",o.tag=a?"strong":"em",o.nesting=-1,o.markup=a?i+i:i,o.content="",a&&(e.tokens[t[r-1].token].content="",e.tokens[t[n.end+1].token].content="",r--))}e.exports.tokenize=function(e,t){var r,n,s=e.pos,o=e.src.charCodeAt(s);if(t)return!1;if(95!==o&&42!==o)return!1;for(n=e.scanDelims(e.pos,42===o),r=0;r{t(e)};acquireNotebookRendererApi("notebookCoreTestRenderer").onDidCreateMarkdown(({element:t,content:r})=>{const n=e.render(r);t.innerHTML=n})}()},function(e,t,r){"use strict";e.exports=r(11)},function(e,t,r){"use strict";var n=r(0),s=r(22),o=r(26),i=r(27),a=r(35),u=r(49),c=r(62),l=r(5),p=r(68),h={default:r(71),zero:r(72),commonmark:r(73)},f=/^(vbscript|javascript|file|data):/,d=/^data:image\/(gif|png|jpeg|webp);/;function m(e){var t=e.trim().toLowerCase();return!f.test(t)||!!d.test(t)}var g=["http:","https:","mailto:"];function _(e){var t=l.parse(e,!0);if(t.hostname&&(!t.protocol||g.indexOf(t.protocol)>=0))try{t.hostname=p.toASCII(t.hostname)}catch(e){}return l.encode(l.format(t))}function b(e){var t=l.parse(e,!0);if(t.hostname&&(!t.protocol||g.indexOf(t.protocol)>=0))try{t.hostname=p.toUnicode(t.hostname)}catch(e){}return l.decode(l.format(t),l.decode.defaultChars+"%")}function k(e,t){if(!(this instanceof k))return new k(e,t);t||n.isString(e)||(t=e||{},e="default"),this.inline=new u,this.block=new a,this.core=new i,this.renderer=new o,this.linkify=new c,this.validateLink=m,this.normalizeLink=_,this.normalizeLinkText=b,this.utils=n,this.helpers=n.assign({},s),this.options={},this.configure(e),t&&this.set(t)}k.prototype.set=function(e){return n.assign(this.options,e),this},k.prototype.configure=function(e){var t,r=this;if(n.isString(e)&&!(e=h[t=e]))throw new Error('Wrong `markdown-it` preset "'+t+'", check name');if(!e)throw new Error("Wrong `markdown-it` preset, can't be empty");return e.options&&r.set(e.options),e.components&&Object.keys(e.components).forEach((function(t){e.components[t].rules&&r[t].ruler.enableOnly(e.components[t].rules),e.components[t].rules2&&r[t].ruler2.enableOnly(e.components[t].rules2)})),this},k.prototype.enable=function(e,t){var r=[];Array.isArray(e)||(e=[e]),["core","block","inline"].forEach((function(t){r=r.concat(this[t].ruler.enable(e,!0))}),this),r=r.concat(this.inline.ruler2.enable(e,!0));var n=e.filter((function(e){return r.indexOf(e)<0}));if(n.length&&!t)throw new Error("MarkdownIt. Failed to enable unknown rule(s): "+n);return this},k.prototype.disable=function(e,t){var r=[];Array.isArray(e)||(e=[e]),["core","block","inline"].forEach((function(t){r=r.concat(this[t].ruler.disable(e,!0))}),this),r=r.concat(this.inline.ruler2.disable(e,!0));var n=e.filter((function(e){return r.indexOf(e)<0}));if(n.length&&!t)throw new Error("MarkdownIt. Failed to disable unknown rule(s): "+n);return this},k.prototype.use=function(e){var t=[this].concat(Array.prototype.slice.call(arguments,1));return e.apply(e,t),this},k.prototype.parse=function(e,t){if("string"!=typeof e)throw new Error("Input data should be a String");var r=new this.core.State(e,this,t);return this.core.process(r),r.tokens},k.prototype.render=function(e,t){return t=t||{},this.renderer.render(this.parse(e,t),this.options,t)},k.prototype.parseInline=function(e,t){var r=new this.core.State(e,this,t);return r.inlineMode=!0,this.core.process(r),r.tokens},k.prototype.renderInline=function(e,t){return t=t||{},this.renderer.render(this.parseInline(e,t),this.options,t)},e.exports=k},function(e){e.exports=JSON.parse('{"Aacute":"Á","aacute":"á","Abreve":"Ă","abreve":"ă","ac":"∾","acd":"∿","acE":"∾̳","Acirc":"Â","acirc":"â","acute":"´","Acy":"А","acy":"а","AElig":"Æ","aelig":"æ","af":"⁡","Afr":"𝔄","afr":"𝔞","Agrave":"À","agrave":"à","alefsym":"ℵ","aleph":"ℵ","Alpha":"Α","alpha":"α","Amacr":"Ā","amacr":"ā","amalg":"⨿","amp":"&","AMP":"&","andand":"⩕","And":"⩓","and":"∧","andd":"⩜","andslope":"⩘","andv":"⩚","ang":"∠","ange":"⦤","angle":"∠","angmsdaa":"⦨","angmsdab":"⦩","angmsdac":"⦪","angmsdad":"⦫","angmsdae":"⦬","angmsdaf":"⦭","angmsdag":"⦮","angmsdah":"⦯","angmsd":"∡","angrt":"∟","angrtvb":"⊾","angrtvbd":"⦝","angsph":"∢","angst":"Å","angzarr":"⍼","Aogon":"Ą","aogon":"ą","Aopf":"𝔸","aopf":"𝕒","apacir":"⩯","ap":"≈","apE":"⩰","ape":"≊","apid":"≋","apos":"\'","ApplyFunction":"⁡","approx":"≈","approxeq":"≊","Aring":"Å","aring":"å","Ascr":"𝒜","ascr":"𝒶","Assign":"≔","ast":"*","asymp":"≈","asympeq":"≍","Atilde":"Ã","atilde":"ã","Auml":"Ä","auml":"ä","awconint":"∳","awint":"⨑","backcong":"≌","backepsilon":"϶","backprime":"‵","backsim":"∽","backsimeq":"⋍","Backslash":"∖","Barv":"⫧","barvee":"⊽","barwed":"⌅","Barwed":"⌆","barwedge":"⌅","bbrk":"⎵","bbrktbrk":"⎶","bcong":"≌","Bcy":"Б","bcy":"б","bdquo":"„","becaus":"∵","because":"∵","Because":"∵","bemptyv":"⦰","bepsi":"϶","bernou":"ℬ","Bernoullis":"ℬ","Beta":"Β","beta":"β","beth":"ℶ","between":"≬","Bfr":"𝔅","bfr":"𝔟","bigcap":"⋂","bigcirc":"◯","bigcup":"⋃","bigodot":"⨀","bigoplus":"⨁","bigotimes":"⨂","bigsqcup":"⨆","bigstar":"★","bigtriangledown":"▽","bigtriangleup":"△","biguplus":"⨄","bigvee":"⋁","bigwedge":"⋀","bkarow":"⤍","blacklozenge":"⧫","blacksquare":"▪","blacktriangle":"▴","blacktriangledown":"▾","blacktriangleleft":"◂","blacktriangleright":"▸","blank":"␣","blk12":"▒","blk14":"░","blk34":"▓","block":"█","bne":"=⃥","bnequiv":"≡⃥","bNot":"⫭","bnot":"⌐","Bopf":"𝔹","bopf":"𝕓","bot":"⊥","bottom":"⊥","bowtie":"⋈","boxbox":"⧉","boxdl":"┐","boxdL":"╕","boxDl":"╖","boxDL":"╗","boxdr":"┌","boxdR":"╒","boxDr":"╓","boxDR":"╔","boxh":"─","boxH":"═","boxhd":"┬","boxHd":"╤","boxhD":"╥","boxHD":"╦","boxhu":"┴","boxHu":"╧","boxhU":"╨","boxHU":"╩","boxminus":"⊟","boxplus":"⊞","boxtimes":"⊠","boxul":"┘","boxuL":"╛","boxUl":"╜","boxUL":"╝","boxur":"└","boxuR":"╘","boxUr":"╙","boxUR":"╚","boxv":"│","boxV":"║","boxvh":"┼","boxvH":"╪","boxVh":"╫","boxVH":"╬","boxvl":"┤","boxvL":"╡","boxVl":"╢","boxVL":"╣","boxvr":"├","boxvR":"╞","boxVr":"╟","boxVR":"╠","bprime":"‵","breve":"˘","Breve":"˘","brvbar":"¦","bscr":"𝒷","Bscr":"ℬ","bsemi":"⁏","bsim":"∽","bsime":"⋍","bsolb":"⧅","bsol":"\\\\","bsolhsub":"⟈","bull":"•","bullet":"•","bump":"≎","bumpE":"⪮","bumpe":"≏","Bumpeq":"≎","bumpeq":"≏","Cacute":"Ć","cacute":"ć","capand":"⩄","capbrcup":"⩉","capcap":"⩋","cap":"∩","Cap":"⋒","capcup":"⩇","capdot":"⩀","CapitalDifferentialD":"ⅅ","caps":"∩︀","caret":"⁁","caron":"ˇ","Cayleys":"ℭ","ccaps":"⩍","Ccaron":"Č","ccaron":"č","Ccedil":"Ç","ccedil":"ç","Ccirc":"Ĉ","ccirc":"ĉ","Cconint":"∰","ccups":"⩌","ccupssm":"⩐","Cdot":"Ċ","cdot":"ċ","cedil":"¸","Cedilla":"¸","cemptyv":"⦲","cent":"¢","centerdot":"·","CenterDot":"·","cfr":"𝔠","Cfr":"ℭ","CHcy":"Ч","chcy":"ч","check":"✓","checkmark":"✓","Chi":"Χ","chi":"χ","circ":"ˆ","circeq":"≗","circlearrowleft":"↺","circlearrowright":"↻","circledast":"⊛","circledcirc":"⊚","circleddash":"⊝","CircleDot":"⊙","circledR":"®","circledS":"Ⓢ","CircleMinus":"⊖","CirclePlus":"⊕","CircleTimes":"⊗","cir":"○","cirE":"⧃","cire":"≗","cirfnint":"⨐","cirmid":"⫯","cirscir":"⧂","ClockwiseContourIntegral":"∲","CloseCurlyDoubleQuote":"”","CloseCurlyQuote":"’","clubs":"♣","clubsuit":"♣","colon":":","Colon":"∷","Colone":"⩴","colone":"≔","coloneq":"≔","comma":",","commat":"@","comp":"∁","compfn":"∘","complement":"∁","complexes":"ℂ","cong":"≅","congdot":"⩭","Congruent":"≡","conint":"∮","Conint":"∯","ContourIntegral":"∮","copf":"𝕔","Copf":"ℂ","coprod":"∐","Coproduct":"∐","copy":"©","COPY":"©","copysr":"℗","CounterClockwiseContourIntegral":"∳","crarr":"↵","cross":"✗","Cross":"⨯","Cscr":"𝒞","cscr":"𝒸","csub":"⫏","csube":"⫑","csup":"⫐","csupe":"⫒","ctdot":"⋯","cudarrl":"⤸","cudarrr":"⤵","cuepr":"⋞","cuesc":"⋟","cularr":"↶","cularrp":"⤽","cupbrcap":"⩈","cupcap":"⩆","CupCap":"≍","cup":"∪","Cup":"⋓","cupcup":"⩊","cupdot":"⊍","cupor":"⩅","cups":"∪︀","curarr":"↷","curarrm":"⤼","curlyeqprec":"⋞","curlyeqsucc":"⋟","curlyvee":"⋎","curlywedge":"⋏","curren":"¤","curvearrowleft":"↶","curvearrowright":"↷","cuvee":"⋎","cuwed":"⋏","cwconint":"∲","cwint":"∱","cylcty":"⌭","dagger":"†","Dagger":"‡","daleth":"ℸ","darr":"↓","Darr":"↡","dArr":"⇓","dash":"‐","Dashv":"⫤","dashv":"⊣","dbkarow":"⤏","dblac":"˝","Dcaron":"Ď","dcaron":"ď","Dcy":"Д","dcy":"д","ddagger":"‡","ddarr":"⇊","DD":"ⅅ","dd":"ⅆ","DDotrahd":"⤑","ddotseq":"⩷","deg":"°","Del":"∇","Delta":"Δ","delta":"δ","demptyv":"⦱","dfisht":"⥿","Dfr":"𝔇","dfr":"𝔡","dHar":"⥥","dharl":"⇃","dharr":"⇂","DiacriticalAcute":"´","DiacriticalDot":"˙","DiacriticalDoubleAcute":"˝","DiacriticalGrave":"`","DiacriticalTilde":"˜","diam":"⋄","diamond":"⋄","Diamond":"⋄","diamondsuit":"♦","diams":"♦","die":"¨","DifferentialD":"ⅆ","digamma":"ϝ","disin":"⋲","div":"÷","divide":"÷","divideontimes":"⋇","divonx":"⋇","DJcy":"Ђ","djcy":"ђ","dlcorn":"⌞","dlcrop":"⌍","dollar":"$","Dopf":"𝔻","dopf":"𝕕","Dot":"¨","dot":"˙","DotDot":"⃜","doteq":"≐","doteqdot":"≑","DotEqual":"≐","dotminus":"∸","dotplus":"∔","dotsquare":"⊡","doublebarwedge":"⌆","DoubleContourIntegral":"∯","DoubleDot":"¨","DoubleDownArrow":"⇓","DoubleLeftArrow":"⇐","DoubleLeftRightArrow":"⇔","DoubleLeftTee":"⫤","DoubleLongLeftArrow":"⟸","DoubleLongLeftRightArrow":"⟺","DoubleLongRightArrow":"⟹","DoubleRightArrow":"⇒","DoubleRightTee":"⊨","DoubleUpArrow":"⇑","DoubleUpDownArrow":"⇕","DoubleVerticalBar":"∥","DownArrowBar":"⤓","downarrow":"↓","DownArrow":"↓","Downarrow":"⇓","DownArrowUpArrow":"⇵","DownBreve":"̑","downdownarrows":"⇊","downharpoonleft":"⇃","downharpoonright":"⇂","DownLeftRightVector":"⥐","DownLeftTeeVector":"⥞","DownLeftVectorBar":"⥖","DownLeftVector":"↽","DownRightTeeVector":"⥟","DownRightVectorBar":"⥗","DownRightVector":"⇁","DownTeeArrow":"↧","DownTee":"⊤","drbkarow":"⤐","drcorn":"⌟","drcrop":"⌌","Dscr":"𝒟","dscr":"𝒹","DScy":"Ѕ","dscy":"ѕ","dsol":"⧶","Dstrok":"Đ","dstrok":"đ","dtdot":"⋱","dtri":"▿","dtrif":"▾","duarr":"⇵","duhar":"⥯","dwangle":"⦦","DZcy":"Џ","dzcy":"џ","dzigrarr":"⟿","Eacute":"É","eacute":"é","easter":"⩮","Ecaron":"Ě","ecaron":"ě","Ecirc":"Ê","ecirc":"ê","ecir":"≖","ecolon":"≕","Ecy":"Э","ecy":"э","eDDot":"⩷","Edot":"Ė","edot":"ė","eDot":"≑","ee":"ⅇ","efDot":"≒","Efr":"𝔈","efr":"𝔢","eg":"⪚","Egrave":"È","egrave":"è","egs":"⪖","egsdot":"⪘","el":"⪙","Element":"∈","elinters":"⏧","ell":"ℓ","els":"⪕","elsdot":"⪗","Emacr":"Ē","emacr":"ē","empty":"∅","emptyset":"∅","EmptySmallSquare":"◻","emptyv":"∅","EmptyVerySmallSquare":"▫","emsp13":" ","emsp14":" ","emsp":" ","ENG":"Ŋ","eng":"ŋ","ensp":" ","Eogon":"Ę","eogon":"ę","Eopf":"𝔼","eopf":"𝕖","epar":"⋕","eparsl":"⧣","eplus":"⩱","epsi":"ε","Epsilon":"Ε","epsilon":"ε","epsiv":"ϵ","eqcirc":"≖","eqcolon":"≕","eqsim":"≂","eqslantgtr":"⪖","eqslantless":"⪕","Equal":"⩵","equals":"=","EqualTilde":"≂","equest":"≟","Equilibrium":"⇌","equiv":"≡","equivDD":"⩸","eqvparsl":"⧥","erarr":"⥱","erDot":"≓","escr":"ℯ","Escr":"ℰ","esdot":"≐","Esim":"⩳","esim":"≂","Eta":"Η","eta":"η","ETH":"Ð","eth":"ð","Euml":"Ë","euml":"ë","euro":"€","excl":"!","exist":"∃","Exists":"∃","expectation":"ℰ","exponentiale":"ⅇ","ExponentialE":"ⅇ","fallingdotseq":"≒","Fcy":"Ф","fcy":"ф","female":"♀","ffilig":"ffi","fflig":"ff","ffllig":"ffl","Ffr":"𝔉","ffr":"𝔣","filig":"fi","FilledSmallSquare":"◼","FilledVerySmallSquare":"▪","fjlig":"fj","flat":"♭","fllig":"fl","fltns":"▱","fnof":"ƒ","Fopf":"𝔽","fopf":"𝕗","forall":"∀","ForAll":"∀","fork":"⋔","forkv":"⫙","Fouriertrf":"ℱ","fpartint":"⨍","frac12":"½","frac13":"⅓","frac14":"¼","frac15":"⅕","frac16":"⅙","frac18":"⅛","frac23":"⅔","frac25":"⅖","frac34":"¾","frac35":"⅗","frac38":"⅜","frac45":"⅘","frac56":"⅚","frac58":"⅝","frac78":"⅞","frasl":"⁄","frown":"⌢","fscr":"𝒻","Fscr":"ℱ","gacute":"ǵ","Gamma":"Γ","gamma":"γ","Gammad":"Ϝ","gammad":"ϝ","gap":"⪆","Gbreve":"Ğ","gbreve":"ğ","Gcedil":"Ģ","Gcirc":"Ĝ","gcirc":"ĝ","Gcy":"Г","gcy":"г","Gdot":"Ġ","gdot":"ġ","ge":"≥","gE":"≧","gEl":"⪌","gel":"⋛","geq":"≥","geqq":"≧","geqslant":"⩾","gescc":"⪩","ges":"⩾","gesdot":"⪀","gesdoto":"⪂","gesdotol":"⪄","gesl":"⋛︀","gesles":"⪔","Gfr":"𝔊","gfr":"𝔤","gg":"≫","Gg":"⋙","ggg":"⋙","gimel":"ℷ","GJcy":"Ѓ","gjcy":"ѓ","gla":"⪥","gl":"≷","glE":"⪒","glj":"⪤","gnap":"⪊","gnapprox":"⪊","gne":"⪈","gnE":"≩","gneq":"⪈","gneqq":"≩","gnsim":"⋧","Gopf":"𝔾","gopf":"𝕘","grave":"`","GreaterEqual":"≥","GreaterEqualLess":"⋛","GreaterFullEqual":"≧","GreaterGreater":"⪢","GreaterLess":"≷","GreaterSlantEqual":"⩾","GreaterTilde":"≳","Gscr":"𝒢","gscr":"ℊ","gsim":"≳","gsime":"⪎","gsiml":"⪐","gtcc":"⪧","gtcir":"⩺","gt":">","GT":">","Gt":"≫","gtdot":"⋗","gtlPar":"⦕","gtquest":"⩼","gtrapprox":"⪆","gtrarr":"⥸","gtrdot":"⋗","gtreqless":"⋛","gtreqqless":"⪌","gtrless":"≷","gtrsim":"≳","gvertneqq":"≩︀","gvnE":"≩︀","Hacek":"ˇ","hairsp":" ","half":"½","hamilt":"ℋ","HARDcy":"Ъ","hardcy":"ъ","harrcir":"⥈","harr":"↔","hArr":"⇔","harrw":"↭","Hat":"^","hbar":"ℏ","Hcirc":"Ĥ","hcirc":"ĥ","hearts":"♥","heartsuit":"♥","hellip":"…","hercon":"⊹","hfr":"𝔥","Hfr":"ℌ","HilbertSpace":"ℋ","hksearow":"⤥","hkswarow":"⤦","hoarr":"⇿","homtht":"∻","hookleftarrow":"↩","hookrightarrow":"↪","hopf":"𝕙","Hopf":"ℍ","horbar":"―","HorizontalLine":"─","hscr":"𝒽","Hscr":"ℋ","hslash":"ℏ","Hstrok":"Ħ","hstrok":"ħ","HumpDownHump":"≎","HumpEqual":"≏","hybull":"⁃","hyphen":"‐","Iacute":"Í","iacute":"í","ic":"⁣","Icirc":"Î","icirc":"î","Icy":"И","icy":"и","Idot":"İ","IEcy":"Е","iecy":"е","iexcl":"¡","iff":"⇔","ifr":"𝔦","Ifr":"ℑ","Igrave":"Ì","igrave":"ì","ii":"ⅈ","iiiint":"⨌","iiint":"∭","iinfin":"⧜","iiota":"℩","IJlig":"IJ","ijlig":"ij","Imacr":"Ī","imacr":"ī","image":"ℑ","ImaginaryI":"ⅈ","imagline":"ℐ","imagpart":"ℑ","imath":"ı","Im":"ℑ","imof":"⊷","imped":"Ƶ","Implies":"⇒","incare":"℅","in":"∈","infin":"∞","infintie":"⧝","inodot":"ı","intcal":"⊺","int":"∫","Int":"∬","integers":"ℤ","Integral":"∫","intercal":"⊺","Intersection":"⋂","intlarhk":"⨗","intprod":"⨼","InvisibleComma":"⁣","InvisibleTimes":"⁢","IOcy":"Ё","iocy":"ё","Iogon":"Į","iogon":"į","Iopf":"𝕀","iopf":"𝕚","Iota":"Ι","iota":"ι","iprod":"⨼","iquest":"¿","iscr":"𝒾","Iscr":"ℐ","isin":"∈","isindot":"⋵","isinE":"⋹","isins":"⋴","isinsv":"⋳","isinv":"∈","it":"⁢","Itilde":"Ĩ","itilde":"ĩ","Iukcy":"І","iukcy":"і","Iuml":"Ï","iuml":"ï","Jcirc":"Ĵ","jcirc":"ĵ","Jcy":"Й","jcy":"й","Jfr":"𝔍","jfr":"𝔧","jmath":"ȷ","Jopf":"𝕁","jopf":"𝕛","Jscr":"𝒥","jscr":"𝒿","Jsercy":"Ј","jsercy":"ј","Jukcy":"Є","jukcy":"є","Kappa":"Κ","kappa":"κ","kappav":"ϰ","Kcedil":"Ķ","kcedil":"ķ","Kcy":"К","kcy":"к","Kfr":"𝔎","kfr":"𝔨","kgreen":"ĸ","KHcy":"Х","khcy":"х","KJcy":"Ќ","kjcy":"ќ","Kopf":"𝕂","kopf":"𝕜","Kscr":"𝒦","kscr":"𝓀","lAarr":"⇚","Lacute":"Ĺ","lacute":"ĺ","laemptyv":"⦴","lagran":"ℒ","Lambda":"Λ","lambda":"λ","lang":"⟨","Lang":"⟪","langd":"⦑","langle":"⟨","lap":"⪅","Laplacetrf":"ℒ","laquo":"«","larrb":"⇤","larrbfs":"⤟","larr":"←","Larr":"↞","lArr":"⇐","larrfs":"⤝","larrhk":"↩","larrlp":"↫","larrpl":"⤹","larrsim":"⥳","larrtl":"↢","latail":"⤙","lAtail":"⤛","lat":"⪫","late":"⪭","lates":"⪭︀","lbarr":"⤌","lBarr":"⤎","lbbrk":"❲","lbrace":"{","lbrack":"[","lbrke":"⦋","lbrksld":"⦏","lbrkslu":"⦍","Lcaron":"Ľ","lcaron":"ľ","Lcedil":"Ļ","lcedil":"ļ","lceil":"⌈","lcub":"{","Lcy":"Л","lcy":"л","ldca":"⤶","ldquo":"“","ldquor":"„","ldrdhar":"⥧","ldrushar":"⥋","ldsh":"↲","le":"≤","lE":"≦","LeftAngleBracket":"⟨","LeftArrowBar":"⇤","leftarrow":"←","LeftArrow":"←","Leftarrow":"⇐","LeftArrowRightArrow":"⇆","leftarrowtail":"↢","LeftCeiling":"⌈","LeftDoubleBracket":"⟦","LeftDownTeeVector":"⥡","LeftDownVectorBar":"⥙","LeftDownVector":"⇃","LeftFloor":"⌊","leftharpoondown":"↽","leftharpoonup":"↼","leftleftarrows":"⇇","leftrightarrow":"↔","LeftRightArrow":"↔","Leftrightarrow":"⇔","leftrightarrows":"⇆","leftrightharpoons":"⇋","leftrightsquigarrow":"↭","LeftRightVector":"⥎","LeftTeeArrow":"↤","LeftTee":"⊣","LeftTeeVector":"⥚","leftthreetimes":"⋋","LeftTriangleBar":"⧏","LeftTriangle":"⊲","LeftTriangleEqual":"⊴","LeftUpDownVector":"⥑","LeftUpTeeVector":"⥠","LeftUpVectorBar":"⥘","LeftUpVector":"↿","LeftVectorBar":"⥒","LeftVector":"↼","lEg":"⪋","leg":"⋚","leq":"≤","leqq":"≦","leqslant":"⩽","lescc":"⪨","les":"⩽","lesdot":"⩿","lesdoto":"⪁","lesdotor":"⪃","lesg":"⋚︀","lesges":"⪓","lessapprox":"⪅","lessdot":"⋖","lesseqgtr":"⋚","lesseqqgtr":"⪋","LessEqualGreater":"⋚","LessFullEqual":"≦","LessGreater":"≶","lessgtr":"≶","LessLess":"⪡","lesssim":"≲","LessSlantEqual":"⩽","LessTilde":"≲","lfisht":"⥼","lfloor":"⌊","Lfr":"𝔏","lfr":"𝔩","lg":"≶","lgE":"⪑","lHar":"⥢","lhard":"↽","lharu":"↼","lharul":"⥪","lhblk":"▄","LJcy":"Љ","ljcy":"љ","llarr":"⇇","ll":"≪","Ll":"⋘","llcorner":"⌞","Lleftarrow":"⇚","llhard":"⥫","lltri":"◺","Lmidot":"Ŀ","lmidot":"ŀ","lmoustache":"⎰","lmoust":"⎰","lnap":"⪉","lnapprox":"⪉","lne":"⪇","lnE":"≨","lneq":"⪇","lneqq":"≨","lnsim":"⋦","loang":"⟬","loarr":"⇽","lobrk":"⟦","longleftarrow":"⟵","LongLeftArrow":"⟵","Longleftarrow":"⟸","longleftrightarrow":"⟷","LongLeftRightArrow":"⟷","Longleftrightarrow":"⟺","longmapsto":"⟼","longrightarrow":"⟶","LongRightArrow":"⟶","Longrightarrow":"⟹","looparrowleft":"↫","looparrowright":"↬","lopar":"⦅","Lopf":"𝕃","lopf":"𝕝","loplus":"⨭","lotimes":"⨴","lowast":"∗","lowbar":"_","LowerLeftArrow":"↙","LowerRightArrow":"↘","loz":"◊","lozenge":"◊","lozf":"⧫","lpar":"(","lparlt":"⦓","lrarr":"⇆","lrcorner":"⌟","lrhar":"⇋","lrhard":"⥭","lrm":"‎","lrtri":"⊿","lsaquo":"‹","lscr":"𝓁","Lscr":"ℒ","lsh":"↰","Lsh":"↰","lsim":"≲","lsime":"⪍","lsimg":"⪏","lsqb":"[","lsquo":"‘","lsquor":"‚","Lstrok":"Ł","lstrok":"ł","ltcc":"⪦","ltcir":"⩹","lt":"<","LT":"<","Lt":"≪","ltdot":"⋖","lthree":"⋋","ltimes":"⋉","ltlarr":"⥶","ltquest":"⩻","ltri":"◃","ltrie":"⊴","ltrif":"◂","ltrPar":"⦖","lurdshar":"⥊","luruhar":"⥦","lvertneqq":"≨︀","lvnE":"≨︀","macr":"¯","male":"♂","malt":"✠","maltese":"✠","Map":"⤅","map":"↦","mapsto":"↦","mapstodown":"↧","mapstoleft":"↤","mapstoup":"↥","marker":"▮","mcomma":"⨩","Mcy":"М","mcy":"м","mdash":"—","mDDot":"∺","measuredangle":"∡","MediumSpace":" ","Mellintrf":"ℳ","Mfr":"𝔐","mfr":"𝔪","mho":"℧","micro":"µ","midast":"*","midcir":"⫰","mid":"∣","middot":"·","minusb":"⊟","minus":"−","minusd":"∸","minusdu":"⨪","MinusPlus":"∓","mlcp":"⫛","mldr":"…","mnplus":"∓","models":"⊧","Mopf":"𝕄","mopf":"𝕞","mp":"∓","mscr":"𝓂","Mscr":"ℳ","mstpos":"∾","Mu":"Μ","mu":"μ","multimap":"⊸","mumap":"⊸","nabla":"∇","Nacute":"Ń","nacute":"ń","nang":"∠⃒","nap":"≉","napE":"⩰̸","napid":"≋̸","napos":"ʼn","napprox":"≉","natural":"♮","naturals":"ℕ","natur":"♮","nbsp":" ","nbump":"≎̸","nbumpe":"≏̸","ncap":"⩃","Ncaron":"Ň","ncaron":"ň","Ncedil":"Ņ","ncedil":"ņ","ncong":"≇","ncongdot":"⩭̸","ncup":"⩂","Ncy":"Н","ncy":"н","ndash":"–","nearhk":"⤤","nearr":"↗","neArr":"⇗","nearrow":"↗","ne":"≠","nedot":"≐̸","NegativeMediumSpace":"​","NegativeThickSpace":"​","NegativeThinSpace":"​","NegativeVeryThinSpace":"​","nequiv":"≢","nesear":"⤨","nesim":"≂̸","NestedGreaterGreater":"≫","NestedLessLess":"≪","NewLine":"\\n","nexist":"∄","nexists":"∄","Nfr":"𝔑","nfr":"𝔫","ngE":"≧̸","nge":"≱","ngeq":"≱","ngeqq":"≧̸","ngeqslant":"⩾̸","nges":"⩾̸","nGg":"⋙̸","ngsim":"≵","nGt":"≫⃒","ngt":"≯","ngtr":"≯","nGtv":"≫̸","nharr":"↮","nhArr":"⇎","nhpar":"⫲","ni":"∋","nis":"⋼","nisd":"⋺","niv":"∋","NJcy":"Њ","njcy":"њ","nlarr":"↚","nlArr":"⇍","nldr":"‥","nlE":"≦̸","nle":"≰","nleftarrow":"↚","nLeftarrow":"⇍","nleftrightarrow":"↮","nLeftrightarrow":"⇎","nleq":"≰","nleqq":"≦̸","nleqslant":"⩽̸","nles":"⩽̸","nless":"≮","nLl":"⋘̸","nlsim":"≴","nLt":"≪⃒","nlt":"≮","nltri":"⋪","nltrie":"⋬","nLtv":"≪̸","nmid":"∤","NoBreak":"⁠","NonBreakingSpace":" ","nopf":"𝕟","Nopf":"ℕ","Not":"⫬","not":"¬","NotCongruent":"≢","NotCupCap":"≭","NotDoubleVerticalBar":"∦","NotElement":"∉","NotEqual":"≠","NotEqualTilde":"≂̸","NotExists":"∄","NotGreater":"≯","NotGreaterEqual":"≱","NotGreaterFullEqual":"≧̸","NotGreaterGreater":"≫̸","NotGreaterLess":"≹","NotGreaterSlantEqual":"⩾̸","NotGreaterTilde":"≵","NotHumpDownHump":"≎̸","NotHumpEqual":"≏̸","notin":"∉","notindot":"⋵̸","notinE":"⋹̸","notinva":"∉","notinvb":"⋷","notinvc":"⋶","NotLeftTriangleBar":"⧏̸","NotLeftTriangle":"⋪","NotLeftTriangleEqual":"⋬","NotLess":"≮","NotLessEqual":"≰","NotLessGreater":"≸","NotLessLess":"≪̸","NotLessSlantEqual":"⩽̸","NotLessTilde":"≴","NotNestedGreaterGreater":"⪢̸","NotNestedLessLess":"⪡̸","notni":"∌","notniva":"∌","notnivb":"⋾","notnivc":"⋽","NotPrecedes":"⊀","NotPrecedesEqual":"⪯̸","NotPrecedesSlantEqual":"⋠","NotReverseElement":"∌","NotRightTriangleBar":"⧐̸","NotRightTriangle":"⋫","NotRightTriangleEqual":"⋭","NotSquareSubset":"⊏̸","NotSquareSubsetEqual":"⋢","NotSquareSuperset":"⊐̸","NotSquareSupersetEqual":"⋣","NotSubset":"⊂⃒","NotSubsetEqual":"⊈","NotSucceeds":"⊁","NotSucceedsEqual":"⪰̸","NotSucceedsSlantEqual":"⋡","NotSucceedsTilde":"≿̸","NotSuperset":"⊃⃒","NotSupersetEqual":"⊉","NotTilde":"≁","NotTildeEqual":"≄","NotTildeFullEqual":"≇","NotTildeTilde":"≉","NotVerticalBar":"∤","nparallel":"∦","npar":"∦","nparsl":"⫽⃥","npart":"∂̸","npolint":"⨔","npr":"⊀","nprcue":"⋠","nprec":"⊀","npreceq":"⪯̸","npre":"⪯̸","nrarrc":"⤳̸","nrarr":"↛","nrArr":"⇏","nrarrw":"↝̸","nrightarrow":"↛","nRightarrow":"⇏","nrtri":"⋫","nrtrie":"⋭","nsc":"⊁","nsccue":"⋡","nsce":"⪰̸","Nscr":"𝒩","nscr":"𝓃","nshortmid":"∤","nshortparallel":"∦","nsim":"≁","nsime":"≄","nsimeq":"≄","nsmid":"∤","nspar":"∦","nsqsube":"⋢","nsqsupe":"⋣","nsub":"⊄","nsubE":"⫅̸","nsube":"⊈","nsubset":"⊂⃒","nsubseteq":"⊈","nsubseteqq":"⫅̸","nsucc":"⊁","nsucceq":"⪰̸","nsup":"⊅","nsupE":"⫆̸","nsupe":"⊉","nsupset":"⊃⃒","nsupseteq":"⊉","nsupseteqq":"⫆̸","ntgl":"≹","Ntilde":"Ñ","ntilde":"ñ","ntlg":"≸","ntriangleleft":"⋪","ntrianglelefteq":"⋬","ntriangleright":"⋫","ntrianglerighteq":"⋭","Nu":"Ν","nu":"ν","num":"#","numero":"№","numsp":" ","nvap":"≍⃒","nvdash":"⊬","nvDash":"⊭","nVdash":"⊮","nVDash":"⊯","nvge":"≥⃒","nvgt":">⃒","nvHarr":"⤄","nvinfin":"⧞","nvlArr":"⤂","nvle":"≤⃒","nvlt":"<⃒","nvltrie":"⊴⃒","nvrArr":"⤃","nvrtrie":"⊵⃒","nvsim":"∼⃒","nwarhk":"⤣","nwarr":"↖","nwArr":"⇖","nwarrow":"↖","nwnear":"⤧","Oacute":"Ó","oacute":"ó","oast":"⊛","Ocirc":"Ô","ocirc":"ô","ocir":"⊚","Ocy":"О","ocy":"о","odash":"⊝","Odblac":"Ő","odblac":"ő","odiv":"⨸","odot":"⊙","odsold":"⦼","OElig":"Œ","oelig":"œ","ofcir":"⦿","Ofr":"𝔒","ofr":"𝔬","ogon":"˛","Ograve":"Ò","ograve":"ò","ogt":"⧁","ohbar":"⦵","ohm":"Ω","oint":"∮","olarr":"↺","olcir":"⦾","olcross":"⦻","oline":"‾","olt":"⧀","Omacr":"Ō","omacr":"ō","Omega":"Ω","omega":"ω","Omicron":"Ο","omicron":"ο","omid":"⦶","ominus":"⊖","Oopf":"𝕆","oopf":"𝕠","opar":"⦷","OpenCurlyDoubleQuote":"“","OpenCurlyQuote":"‘","operp":"⦹","oplus":"⊕","orarr":"↻","Or":"⩔","or":"∨","ord":"⩝","order":"ℴ","orderof":"ℴ","ordf":"ª","ordm":"º","origof":"⊶","oror":"⩖","orslope":"⩗","orv":"⩛","oS":"Ⓢ","Oscr":"𝒪","oscr":"ℴ","Oslash":"Ø","oslash":"ø","osol":"⊘","Otilde":"Õ","otilde":"õ","otimesas":"⨶","Otimes":"⨷","otimes":"⊗","Ouml":"Ö","ouml":"ö","ovbar":"⌽","OverBar":"‾","OverBrace":"⏞","OverBracket":"⎴","OverParenthesis":"⏜","para":"¶","parallel":"∥","par":"∥","parsim":"⫳","parsl":"⫽","part":"∂","PartialD":"∂","Pcy":"П","pcy":"п","percnt":"%","period":".","permil":"‰","perp":"⊥","pertenk":"‱","Pfr":"𝔓","pfr":"𝔭","Phi":"Φ","phi":"φ","phiv":"ϕ","phmmat":"ℳ","phone":"☎","Pi":"Π","pi":"π","pitchfork":"⋔","piv":"ϖ","planck":"ℏ","planckh":"ℎ","plankv":"ℏ","plusacir":"⨣","plusb":"⊞","pluscir":"⨢","plus":"+","plusdo":"∔","plusdu":"⨥","pluse":"⩲","PlusMinus":"±","plusmn":"±","plussim":"⨦","plustwo":"⨧","pm":"±","Poincareplane":"ℌ","pointint":"⨕","popf":"𝕡","Popf":"ℙ","pound":"£","prap":"⪷","Pr":"⪻","pr":"≺","prcue":"≼","precapprox":"⪷","prec":"≺","preccurlyeq":"≼","Precedes":"≺","PrecedesEqual":"⪯","PrecedesSlantEqual":"≼","PrecedesTilde":"≾","preceq":"⪯","precnapprox":"⪹","precneqq":"⪵","precnsim":"⋨","pre":"⪯","prE":"⪳","precsim":"≾","prime":"′","Prime":"″","primes":"ℙ","prnap":"⪹","prnE":"⪵","prnsim":"⋨","prod":"∏","Product":"∏","profalar":"⌮","profline":"⌒","profsurf":"⌓","prop":"∝","Proportional":"∝","Proportion":"∷","propto":"∝","prsim":"≾","prurel":"⊰","Pscr":"𝒫","pscr":"𝓅","Psi":"Ψ","psi":"ψ","puncsp":" ","Qfr":"𝔔","qfr":"𝔮","qint":"⨌","qopf":"𝕢","Qopf":"ℚ","qprime":"⁗","Qscr":"𝒬","qscr":"𝓆","quaternions":"ℍ","quatint":"⨖","quest":"?","questeq":"≟","quot":"\\"","QUOT":"\\"","rAarr":"⇛","race":"∽̱","Racute":"Ŕ","racute":"ŕ","radic":"√","raemptyv":"⦳","rang":"⟩","Rang":"⟫","rangd":"⦒","range":"⦥","rangle":"⟩","raquo":"»","rarrap":"⥵","rarrb":"⇥","rarrbfs":"⤠","rarrc":"⤳","rarr":"→","Rarr":"↠","rArr":"⇒","rarrfs":"⤞","rarrhk":"↪","rarrlp":"↬","rarrpl":"⥅","rarrsim":"⥴","Rarrtl":"⤖","rarrtl":"↣","rarrw":"↝","ratail":"⤚","rAtail":"⤜","ratio":"∶","rationals":"ℚ","rbarr":"⤍","rBarr":"⤏","RBarr":"⤐","rbbrk":"❳","rbrace":"}","rbrack":"]","rbrke":"⦌","rbrksld":"⦎","rbrkslu":"⦐","Rcaron":"Ř","rcaron":"ř","Rcedil":"Ŗ","rcedil":"ŗ","rceil":"⌉","rcub":"}","Rcy":"Р","rcy":"р","rdca":"⤷","rdldhar":"⥩","rdquo":"”","rdquor":"”","rdsh":"↳","real":"ℜ","realine":"ℛ","realpart":"ℜ","reals":"ℝ","Re":"ℜ","rect":"▭","reg":"®","REG":"®","ReverseElement":"∋","ReverseEquilibrium":"⇋","ReverseUpEquilibrium":"⥯","rfisht":"⥽","rfloor":"⌋","rfr":"𝔯","Rfr":"ℜ","rHar":"⥤","rhard":"⇁","rharu":"⇀","rharul":"⥬","Rho":"Ρ","rho":"ρ","rhov":"ϱ","RightAngleBracket":"⟩","RightArrowBar":"⇥","rightarrow":"→","RightArrow":"→","Rightarrow":"⇒","RightArrowLeftArrow":"⇄","rightarrowtail":"↣","RightCeiling":"⌉","RightDoubleBracket":"⟧","RightDownTeeVector":"⥝","RightDownVectorBar":"⥕","RightDownVector":"⇂","RightFloor":"⌋","rightharpoondown":"⇁","rightharpoonup":"⇀","rightleftarrows":"⇄","rightleftharpoons":"⇌","rightrightarrows":"⇉","rightsquigarrow":"↝","RightTeeArrow":"↦","RightTee":"⊢","RightTeeVector":"⥛","rightthreetimes":"⋌","RightTriangleBar":"⧐","RightTriangle":"⊳","RightTriangleEqual":"⊵","RightUpDownVector":"⥏","RightUpTeeVector":"⥜","RightUpVectorBar":"⥔","RightUpVector":"↾","RightVectorBar":"⥓","RightVector":"⇀","ring":"˚","risingdotseq":"≓","rlarr":"⇄","rlhar":"⇌","rlm":"‏","rmoustache":"⎱","rmoust":"⎱","rnmid":"⫮","roang":"⟭","roarr":"⇾","robrk":"⟧","ropar":"⦆","ropf":"𝕣","Ropf":"ℝ","roplus":"⨮","rotimes":"⨵","RoundImplies":"⥰","rpar":")","rpargt":"⦔","rppolint":"⨒","rrarr":"⇉","Rrightarrow":"⇛","rsaquo":"›","rscr":"𝓇","Rscr":"ℛ","rsh":"↱","Rsh":"↱","rsqb":"]","rsquo":"’","rsquor":"’","rthree":"⋌","rtimes":"⋊","rtri":"▹","rtrie":"⊵","rtrif":"▸","rtriltri":"⧎","RuleDelayed":"⧴","ruluhar":"⥨","rx":"℞","Sacute":"Ś","sacute":"ś","sbquo":"‚","scap":"⪸","Scaron":"Š","scaron":"š","Sc":"⪼","sc":"≻","sccue":"≽","sce":"⪰","scE":"⪴","Scedil":"Ş","scedil":"ş","Scirc":"Ŝ","scirc":"ŝ","scnap":"⪺","scnE":"⪶","scnsim":"⋩","scpolint":"⨓","scsim":"≿","Scy":"С","scy":"с","sdotb":"⊡","sdot":"⋅","sdote":"⩦","searhk":"⤥","searr":"↘","seArr":"⇘","searrow":"↘","sect":"§","semi":";","seswar":"⤩","setminus":"∖","setmn":"∖","sext":"✶","Sfr":"𝔖","sfr":"𝔰","sfrown":"⌢","sharp":"♯","SHCHcy":"Щ","shchcy":"щ","SHcy":"Ш","shcy":"ш","ShortDownArrow":"↓","ShortLeftArrow":"←","shortmid":"∣","shortparallel":"∥","ShortRightArrow":"→","ShortUpArrow":"↑","shy":"­","Sigma":"Σ","sigma":"σ","sigmaf":"ς","sigmav":"ς","sim":"∼","simdot":"⩪","sime":"≃","simeq":"≃","simg":"⪞","simgE":"⪠","siml":"⪝","simlE":"⪟","simne":"≆","simplus":"⨤","simrarr":"⥲","slarr":"←","SmallCircle":"∘","smallsetminus":"∖","smashp":"⨳","smeparsl":"⧤","smid":"∣","smile":"⌣","smt":"⪪","smte":"⪬","smtes":"⪬︀","SOFTcy":"Ь","softcy":"ь","solbar":"⌿","solb":"⧄","sol":"/","Sopf":"𝕊","sopf":"𝕤","spades":"♠","spadesuit":"♠","spar":"∥","sqcap":"⊓","sqcaps":"⊓︀","sqcup":"⊔","sqcups":"⊔︀","Sqrt":"√","sqsub":"⊏","sqsube":"⊑","sqsubset":"⊏","sqsubseteq":"⊑","sqsup":"⊐","sqsupe":"⊒","sqsupset":"⊐","sqsupseteq":"⊒","square":"□","Square":"□","SquareIntersection":"⊓","SquareSubset":"⊏","SquareSubsetEqual":"⊑","SquareSuperset":"⊐","SquareSupersetEqual":"⊒","SquareUnion":"⊔","squarf":"▪","squ":"□","squf":"▪","srarr":"→","Sscr":"𝒮","sscr":"𝓈","ssetmn":"∖","ssmile":"⌣","sstarf":"⋆","Star":"⋆","star":"☆","starf":"★","straightepsilon":"ϵ","straightphi":"ϕ","strns":"¯","sub":"⊂","Sub":"⋐","subdot":"⪽","subE":"⫅","sube":"⊆","subedot":"⫃","submult":"⫁","subnE":"⫋","subne":"⊊","subplus":"⪿","subrarr":"⥹","subset":"⊂","Subset":"⋐","subseteq":"⊆","subseteqq":"⫅","SubsetEqual":"⊆","subsetneq":"⊊","subsetneqq":"⫋","subsim":"⫇","subsub":"⫕","subsup":"⫓","succapprox":"⪸","succ":"≻","succcurlyeq":"≽","Succeeds":"≻","SucceedsEqual":"⪰","SucceedsSlantEqual":"≽","SucceedsTilde":"≿","succeq":"⪰","succnapprox":"⪺","succneqq":"⪶","succnsim":"⋩","succsim":"≿","SuchThat":"∋","sum":"∑","Sum":"∑","sung":"♪","sup1":"¹","sup2":"²","sup3":"³","sup":"⊃","Sup":"⋑","supdot":"⪾","supdsub":"⫘","supE":"⫆","supe":"⊇","supedot":"⫄","Superset":"⊃","SupersetEqual":"⊇","suphsol":"⟉","suphsub":"⫗","suplarr":"⥻","supmult":"⫂","supnE":"⫌","supne":"⊋","supplus":"⫀","supset":"⊃","Supset":"⋑","supseteq":"⊇","supseteqq":"⫆","supsetneq":"⊋","supsetneqq":"⫌","supsim":"⫈","supsub":"⫔","supsup":"⫖","swarhk":"⤦","swarr":"↙","swArr":"⇙","swarrow":"↙","swnwar":"⤪","szlig":"ß","Tab":"\\t","target":"⌖","Tau":"Τ","tau":"τ","tbrk":"⎴","Tcaron":"Ť","tcaron":"ť","Tcedil":"Ţ","tcedil":"ţ","Tcy":"Т","tcy":"т","tdot":"⃛","telrec":"⌕","Tfr":"𝔗","tfr":"𝔱","there4":"∴","therefore":"∴","Therefore":"∴","Theta":"Θ","theta":"θ","thetasym":"ϑ","thetav":"ϑ","thickapprox":"≈","thicksim":"∼","ThickSpace":"  ","ThinSpace":" ","thinsp":" ","thkap":"≈","thksim":"∼","THORN":"Þ","thorn":"þ","tilde":"˜","Tilde":"∼","TildeEqual":"≃","TildeFullEqual":"≅","TildeTilde":"≈","timesbar":"⨱","timesb":"⊠","times":"×","timesd":"⨰","tint":"∭","toea":"⤨","topbot":"⌶","topcir":"⫱","top":"⊤","Topf":"𝕋","topf":"𝕥","topfork":"⫚","tosa":"⤩","tprime":"‴","trade":"™","TRADE":"™","triangle":"▵","triangledown":"▿","triangleleft":"◃","trianglelefteq":"⊴","triangleq":"≜","triangleright":"▹","trianglerighteq":"⊵","tridot":"◬","trie":"≜","triminus":"⨺","TripleDot":"⃛","triplus":"⨹","trisb":"⧍","tritime":"⨻","trpezium":"⏢","Tscr":"𝒯","tscr":"𝓉","TScy":"Ц","tscy":"ц","TSHcy":"Ћ","tshcy":"ћ","Tstrok":"Ŧ","tstrok":"ŧ","twixt":"≬","twoheadleftarrow":"↞","twoheadrightarrow":"↠","Uacute":"Ú","uacute":"ú","uarr":"↑","Uarr":"↟","uArr":"⇑","Uarrocir":"⥉","Ubrcy":"Ў","ubrcy":"ў","Ubreve":"Ŭ","ubreve":"ŭ","Ucirc":"Û","ucirc":"û","Ucy":"У","ucy":"у","udarr":"⇅","Udblac":"Ű","udblac":"ű","udhar":"⥮","ufisht":"⥾","Ufr":"𝔘","ufr":"𝔲","Ugrave":"Ù","ugrave":"ù","uHar":"⥣","uharl":"↿","uharr":"↾","uhblk":"▀","ulcorn":"⌜","ulcorner":"⌜","ulcrop":"⌏","ultri":"◸","Umacr":"Ū","umacr":"ū","uml":"¨","UnderBar":"_","UnderBrace":"⏟","UnderBracket":"⎵","UnderParenthesis":"⏝","Union":"⋃","UnionPlus":"⊎","Uogon":"Ų","uogon":"ų","Uopf":"𝕌","uopf":"𝕦","UpArrowBar":"⤒","uparrow":"↑","UpArrow":"↑","Uparrow":"⇑","UpArrowDownArrow":"⇅","updownarrow":"↕","UpDownArrow":"↕","Updownarrow":"⇕","UpEquilibrium":"⥮","upharpoonleft":"↿","upharpoonright":"↾","uplus":"⊎","UpperLeftArrow":"↖","UpperRightArrow":"↗","upsi":"υ","Upsi":"ϒ","upsih":"ϒ","Upsilon":"Υ","upsilon":"υ","UpTeeArrow":"↥","UpTee":"⊥","upuparrows":"⇈","urcorn":"⌝","urcorner":"⌝","urcrop":"⌎","Uring":"Ů","uring":"ů","urtri":"◹","Uscr":"𝒰","uscr":"𝓊","utdot":"⋰","Utilde":"Ũ","utilde":"ũ","utri":"▵","utrif":"▴","uuarr":"⇈","Uuml":"Ü","uuml":"ü","uwangle":"⦧","vangrt":"⦜","varepsilon":"ϵ","varkappa":"ϰ","varnothing":"∅","varphi":"ϕ","varpi":"ϖ","varpropto":"∝","varr":"↕","vArr":"⇕","varrho":"ϱ","varsigma":"ς","varsubsetneq":"⊊︀","varsubsetneqq":"⫋︀","varsupsetneq":"⊋︀","varsupsetneqq":"⫌︀","vartheta":"ϑ","vartriangleleft":"⊲","vartriangleright":"⊳","vBar":"⫨","Vbar":"⫫","vBarv":"⫩","Vcy":"В","vcy":"в","vdash":"⊢","vDash":"⊨","Vdash":"⊩","VDash":"⊫","Vdashl":"⫦","veebar":"⊻","vee":"∨","Vee":"⋁","veeeq":"≚","vellip":"⋮","verbar":"|","Verbar":"‖","vert":"|","Vert":"‖","VerticalBar":"∣","VerticalLine":"|","VerticalSeparator":"❘","VerticalTilde":"≀","VeryThinSpace":" ","Vfr":"𝔙","vfr":"𝔳","vltri":"⊲","vnsub":"⊂⃒","vnsup":"⊃⃒","Vopf":"𝕍","vopf":"𝕧","vprop":"∝","vrtri":"⊳","Vscr":"𝒱","vscr":"𝓋","vsubnE":"⫋︀","vsubne":"⊊︀","vsupnE":"⫌︀","vsupne":"⊋︀","Vvdash":"⊪","vzigzag":"⦚","Wcirc":"Ŵ","wcirc":"ŵ","wedbar":"⩟","wedge":"∧","Wedge":"⋀","wedgeq":"≙","weierp":"℘","Wfr":"𝔚","wfr":"𝔴","Wopf":"𝕎","wopf":"𝕨","wp":"℘","wr":"≀","wreath":"≀","Wscr":"𝒲","wscr":"𝓌","xcap":"⋂","xcirc":"◯","xcup":"⋃","xdtri":"▽","Xfr":"𝔛","xfr":"𝔵","xharr":"⟷","xhArr":"⟺","Xi":"Ξ","xi":"ξ","xlarr":"⟵","xlArr":"⟸","xmap":"⟼","xnis":"⋻","xodot":"⨀","Xopf":"𝕏","xopf":"𝕩","xoplus":"⨁","xotime":"⨂","xrarr":"⟶","xrArr":"⟹","Xscr":"𝒳","xscr":"𝓍","xsqcup":"⨆","xuplus":"⨄","xutri":"△","xvee":"⋁","xwedge":"⋀","Yacute":"Ý","yacute":"ý","YAcy":"Я","yacy":"я","Ycirc":"Ŷ","ycirc":"ŷ","Ycy":"Ы","ycy":"ы","yen":"¥","Yfr":"𝔜","yfr":"𝔶","YIcy":"Ї","yicy":"ї","Yopf":"𝕐","yopf":"𝕪","Yscr":"𝒴","yscr":"𝓎","YUcy":"Ю","yucy":"ю","yuml":"ÿ","Yuml":"Ÿ","Zacute":"Ź","zacute":"ź","Zcaron":"Ž","zcaron":"ž","Zcy":"З","zcy":"з","Zdot":"Ż","zdot":"ż","zeetrf":"ℨ","ZeroWidthSpace":"​","Zeta":"Ζ","zeta":"ζ","zfr":"𝔷","Zfr":"ℨ","ZHcy":"Ж","zhcy":"ж","zigrarr":"⇝","zopf":"𝕫","Zopf":"ℤ","Zscr":"𝒵","zscr":"𝓏","zwj":"‍","zwnj":"‌"}')},function(e,t,r){"use strict";var n={};function s(e,t,r){var o,i,a,u,c,l="";for("string"!=typeof t&&(r=t,t=s.defaultChars),void 0===r&&(r=!0),c=function(e){var t,r,s=n[e];if(s)return s;for(s=n[e]=[],t=0;t<128;t++)r=String.fromCharCode(t),/^[0-9a-z]$/i.test(r)?s.push(r):s.push("%"+("0"+t.toString(16).toUpperCase()).slice(-2));for(t=0;t=55296&&a<=57343){if(a>=55296&&a<=56319&&o+1=56320&&u<=57343){l+=encodeURIComponent(e[o]+e[o+1]),o++;continue}l+="%EF%BF%BD"}else l+=encodeURIComponent(e[o]);return l}s.defaultChars=";/?:@&=+$,-_.!~*'()#",s.componentChars="-_.!~*'()",e.exports=s},function(e,t,r){"use strict";var n={};function s(e,t){var r;return"string"!=typeof t&&(t=s.defaultChars),r=function(e){var t,r,s=n[e];if(s)return s;for(s=n[e]=[],t=0;t<128;t++)r=String.fromCharCode(t),s.push(r);for(t=0;t=55296&&u<=57343?"���":String.fromCharCode(u),t+=6):240==(248&s)&&t+91114111?c+="����":(u-=65536,c+=String.fromCharCode(55296+(u>>10),56320+(1023&u))),t+=9):c+="�";return c}))}s.defaultChars=";/?:@&=+$,#",s.componentChars="",e.exports=s},function(e,t,r){"use strict";e.exports=function(e){var t="";return t+=e.protocol||"",t+=e.slashes?"//":"",t+=e.auth?e.auth+"@":"",e.hostname&&-1!==e.hostname.indexOf(":")?t+="["+e.hostname+"]":t+=e.hostname||"",t+=e.port?":"+e.port:"",t+=e.pathname||"",t+=e.search||"",t+=e.hash||""}},function(e,t,r){"use strict";function n(){this.protocol=null,this.slashes=null,this.auth=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.pathname=null}var s=/^([a-z0-9.+-]+:)/i,o=/:[0-9]*$/,i=/^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,a=["{","}","|","\\","^","`"].concat(["<",">",'"',"`"," ","\r","\n","\t"]),u=["'"].concat(a),c=["%","/","?",";","#"].concat(u),l=["/","?","#"],p=/^[+a-z0-9A-Z_-]{0,63}$/,h=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,f={javascript:!0,"javascript:":!0},d={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0};n.prototype.parse=function(e,t){var r,n,o,a,u,m=e;if(m=m.trim(),!t&&1===e.split("#").length){var g=i.exec(m);if(g)return this.pathname=g[1],g[2]&&(this.search=g[2]),this}var _=s.exec(m);if(_&&(o=(_=_[0]).toLowerCase(),this.protocol=_,m=m.substr(_.length)),(t||_||m.match(/^\/\/[^@\/]+@[^@\/]+/))&&(!(u="//"===m.substr(0,2))||_&&f[_]||(m=m.substr(2),this.slashes=!0)),!f[_]&&(u||_&&!d[_])){var b,k,C=-1;for(r=0;r127?x+="x":x+=y[F];if(!x.match(p)){var w=A.slice(0,r),q=A.slice(r+1),S=y.match(h);S&&(w.push(S[1]),q.unshift(S[2])),q.length&&(m=q.join(".")+m),this.hostname=w.join(".");break}}}}this.hostname.length>255&&(this.hostname=""),D&&(this.hostname=this.hostname.substr(1,this.hostname.length-2))}var L=m.indexOf("#");-1!==L&&(this.hash=m.substr(L),m=m.slice(0,L));var z=m.indexOf("?");return-1!==z&&(this.search=m.substr(z),m=m.slice(0,z)),m&&(this.pathname=m),d[o]&&this.hostname&&!this.pathname&&(this.pathname=""),this},n.prototype.parseHost=function(e){var t=o.exec(e);t&&(":"!==(t=t[0])&&(this.port=t.substr(1)),e=e.substr(0,e.length-t.length)),e&&(this.hostname=e)},e.exports=function(e,t){if(e&&e instanceof n)return e;var r=new n;return r.parse(e,t),r}},function(e,t,r){"use strict";t.Any=r(18),t.Cc=r(19),t.Cf=r(20),t.P=r(4),t.Z=r(21)},function(e,t){e.exports=/[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/},function(e,t){e.exports=/[\0-\x1F\x7F-\x9F]/},function(e,t){e.exports=/[\xAD\u0600-\u0605\u061C\u06DD\u070F\u08E2\u180E\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF\uFFF9-\uFFFB]|\uD804\uDCBD|\uD82F[\uDCA0-\uDCA3]|\uD834[\uDD73-\uDD7A]|\uDB40[\uDC01\uDC20-\uDC7F]/},function(e,t){e.exports=/[ \xA0\u1680\u2000-\u200A\u202F\u205F\u3000]/},function(e,t,r){"use strict";t.parseLinkLabel=r(23),t.parseLinkDestination=r(24),t.parseLinkTitle=r(25)},function(e,t,r){"use strict";e.exports=function(e,t,r){var n,s,o,i,a=-1,u=e.posMax,c=e.pos;for(e.pos=t+1,n=1;e.pos32)return a;if(41===s){if(0===o)break;o--}t++}return i===t||0!==o||(a.str=n(e.slice(i,t)),a.lines=0,a.pos=t,a.ok=!0),a}},function(e,t,r){"use strict";var n=r(0).unescapeAll;e.exports=function(e,t,r){var s,o,i=0,a=t,u={ok:!1,pos:0,lines:0,str:""};if(t>=r)return u;if(34!==(o=e.charCodeAt(t))&&39!==o&&40!==o)return u;for(t++,40===o&&(o=41);t"+o(e[t].content)+""},i.code_block=function(e,t,r,n,s){var i=e[t];return""+o(e[t].content)+"\n"},i.fence=function(e,t,r,n,i){var a,u,c,l,p,h=e[t],f=h.info?s(h.info).trim():"",d="",m="";return f&&(d=(c=f.split(/(\s+)/g))[0],m=c.slice(2).join("")),0===(a=r.highlight&&r.highlight(h.content,d,m)||o(h.content)).indexOf(""+a+"\n"):"
"+a+"
\n"},i.image=function(e,t,r,n,s){var o=e[t];return o.attrs[o.attrIndex("alt")][1]=s.renderInlineAsText(o.children,r,n),s.renderToken(e,t,r)},i.hardbreak=function(e,t,r){return r.xhtmlOut?"
\n":"
\n"},i.softbreak=function(e,t,r){return r.breaks?r.xhtmlOut?"
\n":"
\n":"\n"},i.text=function(e,t){return o(e[t].content)},i.html_block=function(e,t){return e[t].content},i.html_inline=function(e,t){return e[t].content},a.prototype.renderAttrs=function(e){var t,r,n;if(!e.attrs)return"";for(n="",t=0,r=e.attrs.length;t\n":">")},a.prototype.renderInline=function(e,t,r){for(var n,s="",o=this.rules,i=0,a=e.length;i/i.test(e)}e.exports=function(e){var t,r,o,i,a,u,c,l,p,h,f,d,m,g,_,b,k,C,v=e.tokens;if(e.md.options.linkify)for(r=0,o=v.length;r=0;t--)if("link_close"!==(u=i[t]).type){if("html_inline"===u.type&&(C=u.content,/^\s]/i.test(C)&&m>0&&m--,s(u.content)&&m++),!(m>0)&&"text"===u.type&&e.md.linkify.test(u.content)){for(p=u.content,k=e.md.linkify.match(p),c=[],d=u.level,f=0,l=0;lf&&((a=new e.Token("text","",0)).content=p.slice(f,h),a.level=d,c.push(a)),(a=new e.Token("link_open","a",1)).attrs=[["href",_]],a.level=d++,a.markup="linkify",a.info="auto",c.push(a),(a=new e.Token("text","",0)).content=b,a.level=d,c.push(a),(a=new e.Token("link_close","a",-1)).level=--d,a.markup="linkify",a.info="auto",c.push(a),f=k[l].lastIndex);f=0;t--)"text"!==(r=e[t]).type||n||(r.content=r.content.replace(o,a)),"link_open"===r.type&&"auto"===r.info&&n--,"link_close"===r.type&&"auto"===r.info&&n++}function c(e){var t,r,s=0;for(t=e.length-1;t>=0;t--)"text"!==(r=e[t]).type||s||n.test(r.content)&&(r.content=r.content.replace(/\+-/g,"±").replace(/\.{2,}/g,"…").replace(/([?!])…/g,"$1..").replace(/([?!]){4,}/g,"$1$1$1").replace(/,{2,}/g,",").replace(/(^|[^-])---(?=[^-]|$)/gm,"$1—").replace(/(^|\s)--(?=\s|$)/gm,"$1–").replace(/(^|[^-\s])--(?=[^-\s]|$)/gm,"$1–")),"link_open"===r.type&&"auto"===r.info&&s--,"link_close"===r.type&&"auto"===r.info&&s++}e.exports=function(e){var t;if(e.md.options.typographer)for(t=e.tokens.length-1;t>=0;t--)"inline"===e.tokens[t].type&&(s.test(e.tokens[t].content)&&u(e.tokens[t].children),n.test(e.tokens[t].content)&&c(e.tokens[t].children))}},function(e,t,r){"use strict";var n=r(0).isWhiteSpace,s=r(0).isPunctChar,o=r(0).isMdAsciiPunct,i=/['"]/,a=/['"]/g;function u(e,t,r){return e.substr(0,t)+r+e.substr(t+1)}function c(e,t){var r,i,c,l,p,h,f,d,m,g,_,b,k,C,v,D,A,y,x,F,E;for(x=[],r=0;r=0&&!(x[A].level<=f);A--);if(x.length=A+1,"text"===i.type){p=0,h=(c=i.content).length;e:for(;p=0)m=c.charCodeAt(l.index-1);else for(A=r-1;A>=0&&("softbreak"!==e[A].type&&"hardbreak"!==e[A].type);A--)if(e[A].content){m=e[A].content.charCodeAt(e[A].content.length-1);break}if(g=32,p=48&&m<=57&&(D=v=!1),v&&D&&(v=_,D=b),v||D){if(D)for(A=x.length-1;A>=0&&(d=x[A],!(x[A].level=0;t--)"inline"===e.tokens[t].type&&i.test(e.tokens[t].content)&&c(e.tokens[t].children,e)}},function(e,t,r){"use strict";var n=r(2);function s(e,t,r){this.src=e,this.env=r,this.tokens=[],this.inlineMode=!1,this.md=t}s.prototype.Token=n,e.exports=s},function(e,t,r){"use strict";var n=r(1),s=[["table",r(36),["paragraph","reference"]],["code",r(37)],["fence",r(38),["paragraph","reference","blockquote","list"]],["blockquote",r(39),["paragraph","reference","blockquote","list"]],["hr",r(40),["paragraph","reference","blockquote","list"]],["list",r(41),["paragraph","reference","blockquote"]],["reference",r(42)],["heading",r(43),["paragraph","reference","blockquote"]],["lheading",r(44)],["html_block",r(45),["paragraph","reference","blockquote"]],["paragraph",r(47)]];function o(){this.ruler=new n;for(var e=0;e=r))&&!(e.sCount[i]=u){e.line=r;break}for(n=0;nr)return!1;if(h=t+1,e.sCount[h]=4)return!1;if((c=e.bMarks[h]+e.tShift[h])>=e.eMarks[h])return!1;if(124!==(a=e.src.charCodeAt(c++))&&45!==a&&58!==a)return!1;for(;c=4)return!1;if((f=o(u)).length&&""===f[0]&&f.shift(),f.length&&""===f[f.length-1]&&f.pop(),0===(d=f.length)||d!==g.length)return!1;if(i)return!0;for(C=e.parentType,e.parentType="table",D=e.md.block.ruler.getRules("blockquote"),(m=e.push("table_open","table",1)).map=b=[t,0],(m=e.push("thead_open","thead",1)).map=[t,t+1],(m=e.push("tr_open","tr",1)).map=[t,t+1],l=0;l=4)break;for((f=o(u)).length&&""===f[0]&&f.shift(),f.length&&""===f[f.length-1]&&f.pop(),h===t+2&&((m=e.push("tbody_open","tbody",1)).map=k=[t+2,0]),(m=e.push("tr_open","tr",1)).map=[h,h+1],l=0;l=4))break;s=++n}return e.line=s,(o=e.push("code_block","code",0)).content=e.getLines(t,s,4+e.blkIndent,!0),o.map=[t,e.line],!0}},function(e,t,r){"use strict";e.exports=function(e,t,r,n){var s,o,i,a,u,c,l,p=!1,h=e.bMarks[t]+e.tShift[t],f=e.eMarks[t];if(e.sCount[t]-e.blkIndent>=4)return!1;if(h+3>f)return!1;if(126!==(s=e.src.charCodeAt(h))&&96!==s)return!1;if(u=h,(o=(h=e.skipChars(h,s))-u)<3)return!1;if(l=e.src.slice(u,h),i=e.src.slice(h,f),96===s&&i.indexOf(String.fromCharCode(s))>=0)return!1;if(n)return!0;for(a=t;!(++a>=r)&&!((h=u=e.bMarks[a]+e.tShift[a])<(f=e.eMarks[a])&&e.sCount[a]=4||(h=e.skipChars(h,s))-u=4)return!1;if(62!==e.src.charCodeAt(F++))return!1;if(s)return!0;for(u=f=e.sCount[t]+1,32===e.src.charCodeAt(F)?(F++,u++,f++,o=!1,C=!0):9===e.src.charCodeAt(F)?(C=!0,(e.bsCount[t]+f)%4==3?(F++,u++,f++,o=!1):o=!0):C=!1,d=[e.bMarks[t]],e.bMarks[t]=F;F=E,b=[e.sCount[t]],e.sCount[t]=f-u,k=[e.tShift[t]],e.tShift[t]=F-e.bMarks[t],D=e.md.block.ruler.getRules("blockquote"),_=e.parentType,e.parentType="blockquote",h=t+1;h=(E=e.eMarks[h])));h++)if(62!==e.src.charCodeAt(F++)||y){if(l)break;for(v=!1,a=0,c=D.length;a=E,m.push(e.bsCount[h]),e.bsCount[h]=e.sCount[h]+1+(C?1:0),b.push(e.sCount[h]),e.sCount[h]=f-u,k.push(e.tShift[h]),e.tShift[h]=F-e.bMarks[h]}for(g=e.blkIndent,e.blkIndent=0,(A=e.push("blockquote_open","blockquote",1)).markup=">",A.map=p=[t,0],e.md.block.tokenize(e,t,h),(A=e.push("blockquote_close","blockquote",-1)).markup=">",e.lineMax=x,e.parentType=_,p[1]=e.line,a=0;a=4)return!1;if(42!==(o=e.src.charCodeAt(c++))&&45!==o&&95!==o)return!1;for(i=1;c=i)return-1;if((r=e.src.charCodeAt(o++))<48||r>57)return-1;for(;;){if(o>=i)return-1;if(!((r=e.src.charCodeAt(o++))>=48&&r<=57)){if(41===r||46===r)break;return-1}if(o-s>=10)return-1}return o=4)return!1;if(e.listIndent>=0&&e.sCount[t]-e.listIndent>=4&&e.sCount[t]=e.blkIndent&&(B=!0),(w=o(e,t))>=0){if(h=!0,S=e.bMarks[t]+e.tShift[t],b=Number(e.src.substr(S,w-S-1)),B&&1!==b)return!1}else{if(!((w=s(e,t))>=0))return!1;h=!1}if(B&&e.skipSpaces(w)>=e.eMarks[t])return!1;if(_=e.src.charCodeAt(w-1),n)return!0;for(g=e.tokens.length,h?(T=e.push("ordered_list_open","ol",1),1!==b&&(T.attrs=[["start",b]])):T=e.push("bullet_list_open","ul",1),T.map=m=[t,0],T.markup=String.fromCharCode(_),C=t,q=!1,z=e.md.block.ruler.getRules("list"),A=e.parentType,e.parentType="list";C=k?1:v-p)>4&&(l=1),c=p+l,(T=e.push("list_item_open","li",1)).markup=String.fromCharCode(_),T.map=f=[t,0],F=e.tight,x=e.tShift[t],y=e.sCount[t],D=e.listIndent,e.listIndent=e.blkIndent,e.blkIndent=c,e.tight=!0,e.tShift[t]=a-e.bMarks[t],e.sCount[t]=v,a>=k&&e.isEmpty(t+1)?e.line=Math.min(e.line+2,r):e.md.block.tokenize(e,t,r,!0),e.tight&&!q||(I=!1),q=e.line-t>1&&e.isEmpty(e.line-1),e.blkIndent=e.listIndent,e.listIndent=D,e.tShift[t]=x,e.sCount[t]=y,e.tight=F,(T=e.push("list_item_close","li",-1)).markup=String.fromCharCode(_),C=t=e.line,f[1]=C,a=e.bMarks[t],C>=r)break;if(e.sCount[C]=4)break;for(L=!1,u=0,d=z.length;u=4)return!1;if(91!==e.src.charCodeAt(A))return!1;for(;++A3||e.sCount[x]<0)){for(k=!1,p=0,h=C.length;p=4)return!1;if(35!==(o=e.src.charCodeAt(c))||c>=l)return!1;for(i=1,o=e.src.charCodeAt(++c);35===o&&c6||cc&&n(e.src.charCodeAt(a-1))&&(l=a),e.line=t+1,(u=e.push("heading_open","h"+String(i),1)).markup="########".slice(0,i),u.map=[t,e.line],(u=e.push("inline","",0)).content=e.src.slice(c,l).trim(),u.map=[t,e.line],u.children=[],(u=e.push("heading_close","h"+String(i),-1)).markup="########".slice(0,i)),!0)}},function(e,t,r){"use strict";e.exports=function(e,t,r){var n,s,o,i,a,u,c,l,p,h,f=t+1,d=e.md.block.ruler.getRules("paragraph");if(e.sCount[t]-e.blkIndent>=4)return!1;for(h=e.parentType,e.parentType="paragraph";f3)){if(e.sCount[f]>=e.blkIndent&&(u=e.bMarks[f]+e.tShift[f])<(c=e.eMarks[f])&&(45===(p=e.src.charCodeAt(u))||61===p)&&(u=e.skipChars(u,p),(u=e.skipSpaces(u))>=c)){l=61===p?1:2;break}if(!(e.sCount[f]<0)){for(s=!1,o=0,i=d.length;o|$))/i,/<\/(script|pre|style)>/i,!0],[/^/,!0],[/^<\?/,/\?>/,!0],[/^/,!0],[/^/,!0],[new RegExp("^|$))","i"),/^$/,!0],[new RegExp(s.source+"\\s*$"),/^$/,!1]];e.exports=function(e,t,r,n){var s,i,a,u,c=e.bMarks[t]+e.tShift[t],l=e.eMarks[t];if(e.sCount[t]-e.blkIndent>=4)return!1;if(!e.md.options.html)return!1;if(60!==e.src.charCodeAt(c))return!1;for(u=e.src.slice(c,l),s=0;s3||e.sCount[u]<0)){for(n=!1,s=0,o=c.length;s0&&this.level++,this.tokens.push(s),s},o.prototype.isEmpty=function(e){return this.bMarks[e]+this.tShift[e]>=this.eMarks[e]},o.prototype.skipEmptyLines=function(e){for(var t=this.lineMax;et;)if(!s(this.src.charCodeAt(--e)))return e+1;return e},o.prototype.skipChars=function(e,t){for(var r=this.src.length;er;)if(t!==this.src.charCodeAt(--e))return e+1;return e},o.prototype.getLines=function(e,t,r,n){var o,i,a,u,c,l,p,h=e;if(e>=t)return"";for(l=new Array(t-e),o=0;hr?new Array(i-r+1).join(" ")+this.src.slice(u,c):this.src.slice(u,c)}return l.join("")},o.prototype.Token=n,e.exports=o},function(e,t,r){"use strict";var n=r(1),s=[["text",r(50)],["newline",r(51)],["escape",r(52)],["backticks",r(53)],["strikethrough",r(7).tokenize],["emphasis",r(8).tokenize],["link",r(54)],["image",r(55)],["autolink",r(56)],["html_inline",r(57)],["entity",r(58)]],o=[["balance_pairs",r(59)],["strikethrough",r(7).postProcess],["emphasis",r(8).postProcess],["text_collapse",r(60)]];function i(){var e;for(this.ruler=new n,e=0;e=o)break}else e.pending+=e.src[e.pos++]}e.pending&&e.pushPending()},i.prototype.parse=function(e,t,r,n){var s,o,i,a=new this.State(e,t,r,n);for(this.tokenize(a),i=(o=this.ruler2.getRules("")).length,s=0;s=0&&32===e.pending.charCodeAt(r)?r>=1&&32===e.pending.charCodeAt(r-1)?(e.pending=e.pending.replace(/ +$/,""),e.push("hardbreak","br",0)):(e.pending=e.pending.slice(0,-1),e.push("softbreak","br",0)):e.push("softbreak","br",0)),o++;o?@[]^_`{|}~-".split("").forEach((function(e){s[e.charCodeAt(0)]=1})),e.exports=function(e,t){var r,o=e.pos,i=e.posMax;if(92!==e.src.charCodeAt(o))return!1;if(++o=m)return!1;if(g=c,(l=e.md.helpers.parseLinkDestination(e.src,c,e.posMax)).ok){for(h=e.md.normalizeLink(l.str),e.md.validateLink(h)?c=l.pos:h="",g=c;c=m||41!==e.src.charCodeAt(c))&&(_=!0),c++}if(_){if(void 0===e.env.references)return!1;if(c=0?i=e.src.slice(g,c++):c=a+1):c=a+1,i||(i=e.src.slice(u,a)),!(p=e.env.references[n(i)]))return e.pos=d,!1;h=p.href,f=p.title}return t||(e.pos=u,e.posMax=a,e.push("link_open","a",1).attrs=r=[["href",h]],f&&r.push(["title",f]),e.md.inline.tokenize(e),e.push("link_close","a",-1)),e.pos=c,e.posMax=m,!0}},function(e,t,r){"use strict";var n=r(0).normalizeReference,s=r(0).isSpace;e.exports=function(e,t){var r,o,i,a,u,c,l,p,h,f,d,m,g,_="",b=e.pos,k=e.posMax;if(33!==e.src.charCodeAt(e.pos))return!1;if(91!==e.src.charCodeAt(e.pos+1))return!1;if(c=e.pos+2,(u=e.md.helpers.parseLinkLabel(e,e.pos+1,!1))<0)return!1;if((l=u+1)=k)return!1;for(g=l,(h=e.md.helpers.parseLinkDestination(e.src,l,e.posMax)).ok&&(_=e.md.normalizeLink(h.str),e.md.validateLink(_)?l=h.pos:_=""),g=l;l=k||41!==e.src.charCodeAt(l))return e.pos=b,!1;l++}else{if(void 0===e.env.references)return!1;if(l=0?a=e.src.slice(g,l++):l=u+1):l=u+1,a||(a=e.src.slice(c,u)),!(p=e.env.references[n(a)]))return e.pos=b,!1;_=p.href,f=p.title}return t||(i=e.src.slice(c,u),e.md.inline.parse(i,e.md,e.env,m=[]),(d=e.push("image","img",0)).attrs=r=[["src",_],["alt",""]],d.children=m,d.content=i,f&&r.push(["title",f])),e.pos=l,e.posMax=k,!0}},function(e,t,r){"use strict";var n=/^([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)$/,s=/^([a-zA-Z][a-zA-Z0-9+.\-]{1,31}):([^<>\x00-\x20]*)$/;e.exports=function(e,t){var r,o,i,a,u,c,l=e.pos;if(60!==e.src.charCodeAt(l))return!1;for(u=e.pos,c=e.posMax;;){if(++l>=c)return!1;if(60===(a=e.src.charCodeAt(l)))return!1;if(62===a)break}return r=e.src.slice(u+1,l),s.test(r)?(o=e.md.normalizeLink(r),!!e.md.validateLink(o)&&(t||((i=e.push("link_open","a",1)).attrs=[["href",o]],i.markup="autolink",i.info="auto",(i=e.push("text","",0)).content=e.md.normalizeLinkText(r),(i=e.push("link_close","a",-1)).markup="autolink",i.info="auto"),e.pos+=r.length+2,!0)):!!n.test(r)&&(o=e.md.normalizeLink("mailto:"+r),!!e.md.validateLink(o)&&(t||((i=e.push("link_open","a",1)).attrs=[["href",o]],i.markup="autolink",i.info="auto",(i=e.push("text","",0)).content=e.md.normalizeLinkText(r),(i=e.push("link_close","a",-1)).markup="autolink",i.info="auto"),e.pos+=r.length+2,!0))}},function(e,t,r){"use strict";var n=r(6).HTML_TAG_RE;e.exports=function(e,t){var r,s,o,i=e.pos;return!!e.md.options.html&&(o=e.posMax,!(60!==e.src.charCodeAt(i)||i+2>=o)&&(!(33!==(r=e.src.charCodeAt(i+1))&&63!==r&&47!==r&&!function(e){var t=32|e;return t>=97&&t<=122}(r))&&(!!(s=e.src.slice(i).match(n))&&(t||(e.push("html_inline","",0).content=e.src.slice(i,i+s[0].length)),e.pos+=s[0].length,!0))))}},function(e,t,r){"use strict";var n=r(3),s=r(0).has,o=r(0).isValidEntityCode,i=r(0).fromCodePoint,a=/^&#((?:x[a-f0-9]{1,6}|[0-9]{1,7}));/i,u=/^&([a-z][a-z0-9]{1,31});/i;e.exports=function(e,t){var r,c,l=e.pos,p=e.posMax;if(38!==e.src.charCodeAt(l))return!1;if(l+1i;n-=o.jump+1)if((o=t[n]).marker===s.marker&&o.open&&o.end<0&&(u=!1,(o.close||s.open)&&(o.length+s.length)%3==0&&(o.length%3==0&&s.length%3==0||(u=!0)),!u)){c=n>0&&!t[n-1].open?t[n-1].jump+1:0,s.jump=r-n+c,s.open=!1,o.end=r,o.jump=c,o.close=!1,a=-1;break}-1!==a&&(l[s.marker][(s.length||0)%3]=a)}}e.exports=function(e){var t,r=e.tokens_meta,s=e.tokens_meta.length;for(n(0,e.delimiters),t=0;t0&&n++,"text"===s[t].type&&t+10&&(this.level++,this._prev_delimiters.push(this.delimiters),this.delimiters=[],o={delimiters:this.delimiters}),this.pendingLevel=this.level,this.tokens.push(s),this.tokens_meta.push(o),s},a.prototype.scanDelims=function(e,t){var r,n,a,u,c,l,p,h,f,d=e,m=!0,g=!0,_=this.posMax,b=this.src.charCodeAt(e);for(r=e>0?this.src.charCodeAt(e-1):32;d<_&&this.src.charCodeAt(d)===b;)d++;return a=d-e,n=d<_?this.src.charCodeAt(d):32,p=i(r)||o(String.fromCharCode(r)),f=i(n)||o(String.fromCharCode(n)),l=s(r),(h=s(n))?m=!1:f&&(l||p||(m=!1)),l?g=!1:p&&(h||f||(g=!1)),t?(u=m,c=g):(u=m&&(!g||p),c=g&&(!m||f)),{can_open:u,can_close:c,length:a}},a.prototype.Token=n,e.exports=a},function(e,t,r){"use strict";function n(e){var t=Array.prototype.slice.call(arguments,1);return t.forEach((function(t){t&&Object.keys(t).forEach((function(r){e[r]=t[r]}))})),e}function s(e){return Object.prototype.toString.call(e)}function o(e){return"[object Function]"===s(e)}function i(e){return e.replace(/[.?*+^$[\]\\(){}|-]/g,"\\$&")}var a={fuzzyLink:!0,fuzzyEmail:!0,fuzzyIP:!1};var u={"http:":{validate:function(e,t,r){var n=e.slice(t);return r.re.http||(r.re.http=new RegExp("^\\/\\/"+r.re.src_auth+r.re.src_host_port_strict+r.re.src_path,"i")),r.re.http.test(n)?n.match(r.re.http)[0].length:0}},"https:":"http:","ftp:":"http:","//":{validate:function(e,t,r){var n=e.slice(t);return r.re.no_http||(r.re.no_http=new RegExp("^"+r.re.src_auth+"(?:localhost|(?:(?:"+r.re.src_domain+")\\.)+"+r.re.src_domain_root+")"+r.re.src_port+r.re.src_host_terminator+r.re.src_path,"i")),r.re.no_http.test(n)?t>=3&&":"===e[t-3]||t>=3&&"/"===e[t-3]?0:n.match(r.re.no_http)[0].length:0}},"mailto:":{validate:function(e,t,r){var n=e.slice(t);return r.re.mailto||(r.re.mailto=new RegExp("^"+r.re.src_email_name+"@"+r.re.src_host_strict,"i")),r.re.mailto.test(n)?n.match(r.re.mailto)[0].length:0}}},c="biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|рф".split("|");function l(e){var t=e.re=r(63)(e.__opts__),n=e.__tlds__.slice();function a(e){return e.replace("%TLDS%",t.src_tlds)}e.onCompile(),e.__tlds_replaced__||n.push("a[cdefgilmnoqrstuwxz]|b[abdefghijmnorstvwyz]|c[acdfghiklmnoruvwxyz]|d[ejkmoz]|e[cegrstu]|f[ijkmor]|g[abdefghilmnpqrstuwy]|h[kmnrtu]|i[delmnoqrst]|j[emop]|k[eghimnprwyz]|l[abcikrstuvy]|m[acdeghklmnopqrstuvwxyz]|n[acefgilopruz]|om|p[aefghklmnrstwy]|qa|r[eosuw]|s[abcdeghijklmnortuvxyz]|t[cdfghjklmnortvwz]|u[agksyz]|v[aceginu]|w[fs]|y[et]|z[amw]"),n.push(t.src_xn),t.src_tlds=n.join("|"),t.email_fuzzy=RegExp(a(t.tpl_email_fuzzy),"i"),t.link_fuzzy=RegExp(a(t.tpl_link_fuzzy),"i"),t.link_no_ip_fuzzy=RegExp(a(t.tpl_link_no_ip_fuzzy),"i"),t.host_fuzzy_test=RegExp(a(t.tpl_host_fuzzy_test),"i");var u=[];function c(e,t){throw new Error('(LinkifyIt) Invalid schema "'+e+'": '+t)}e.__compiled__={},Object.keys(e.__schemas__).forEach((function(t){var r=e.__schemas__[t];if(null!==r){var n={validate:null,link:null};if(e.__compiled__[t]=n,"[object Object]"===s(r))return!function(e){return"[object RegExp]"===s(e)}(r.validate)?o(r.validate)?n.validate=r.validate:c(t,r):n.validate=function(e){return function(t,r){var n=t.slice(r);return e.test(n)?n.match(e)[0].length:0}}(r.validate),void(o(r.normalize)?n.normalize=r.normalize:r.normalize?c(t,r):n.normalize=function(e,t){t.normalize(e)});!function(e){return"[object String]"===s(e)}(r)?c(t,r):u.push(t)}})),u.forEach((function(t){e.__compiled__[e.__schemas__[t]]&&(e.__compiled__[t].validate=e.__compiled__[e.__schemas__[t]].validate,e.__compiled__[t].normalize=e.__compiled__[e.__schemas__[t]].normalize)})),e.__compiled__[""]={validate:null,normalize:function(e,t){t.normalize(e)}};var l=Object.keys(e.__compiled__).filter((function(t){return t.length>0&&e.__compiled__[t]})).map(i).join("|");e.re.schema_test=RegExp("(^|(?!_)(?:[><|]|"+t.src_ZPCc+"))("+l+")","i"),e.re.schema_search=RegExp("(^|(?!_)(?:[><|]|"+t.src_ZPCc+"))("+l+")","ig"),e.re.pretest=RegExp("("+e.re.schema_test.source+")|("+e.re.host_fuzzy_test.source+")|@","i"),function(e){e.__index__=-1,e.__text_cache__=""}(e)}function p(e,t){var r=e.__index__,n=e.__last_index__,s=e.__text_cache__.slice(r,n);this.schema=e.__schema__.toLowerCase(),this.index=r+t,this.lastIndex=n+t,this.raw=s,this.text=s,this.url=s}function h(e,t){var r=new p(e,t);return e.__compiled__[r.schema].normalize(r,e),r}function f(e,t){if(!(this instanceof f))return new f(e,t);var r;t||(r=e,Object.keys(r||{}).reduce((function(e,t){return e||a.hasOwnProperty(t)}),!1)&&(t=e,e={})),this.__opts__=n({},a,t),this.__index__=-1,this.__last_index__=-1,this.__schema__="",this.__text_cache__="",this.__schemas__=n({},u,e),this.__compiled__={},this.__tlds__=c,this.__tlds_replaced__=!1,this.re={},l(this)}f.prototype.add=function(e,t){return this.__schemas__[e]=t,l(this),this},f.prototype.set=function(e){return this.__opts__=n(this.__opts__,e),this},f.prototype.test=function(e){if(this.__text_cache__=e,this.__index__=-1,!e.length)return!1;var t,r,n,s,o,i,a,u;if(this.re.schema_test.test(e))for((a=this.re.schema_search).lastIndex=0;null!==(t=a.exec(e));)if(s=this.testSchemaAt(e,t[2],a.lastIndex)){this.__schema__=t[2],this.__index__=t.index+t[1].length,this.__last_index__=t.index+t[0].length+s;break}return this.__opts__.fuzzyLink&&this.__compiled__["http:"]&&(u=e.search(this.re.host_fuzzy_test))>=0&&(this.__index__<0||u=0&&null!==(n=e.match(this.re.email_fuzzy))&&(o=n.index+n[1].length,i=n.index+n[0].length,(this.__index__<0||othis.__last_index__)&&(this.__schema__="mailto:",this.__index__=o,this.__last_index__=i)),this.__index__>=0},f.prototype.pretest=function(e){return this.re.pretest.test(e)},f.prototype.testSchemaAt=function(e,t,r){return this.__compiled__[t.toLowerCase()]?this.__compiled__[t.toLowerCase()].validate(e,r,this):0},f.prototype.match=function(e){var t=0,r=[];this.__index__>=0&&this.__text_cache__===e&&(r.push(h(this,t)),t=this.__last_index__);for(var n=t?e.slice(t):e;this.test(n);)r.push(h(this,t)),n=n.slice(this.__last_index__),t+=this.__last_index__;return r.length?r:null},f.prototype.tlds=function(e,t){return e=Array.isArray(e)?e:[e],t?(this.__tlds__=this.__tlds__.concat(e).sort().filter((function(e,t,r){return e!==r[t-1]})).reverse(),l(this),this):(this.__tlds__=e.slice(),this.__tlds_replaced__=!0,l(this),this)},f.prototype.normalize=function(e){e.schema||(e.url="http://"+e.url),"mailto:"!==e.schema||/^mailto:/i.test(e.url)||(e.url="mailto:"+e.url)},f.prototype.onCompile=function(){},e.exports=f},function(e,t,r){"use strict";e.exports=function(e){var t={};t.src_Any=r(64).source,t.src_Cc=r(65).source,t.src_Z=r(66).source,t.src_P=r(67).source,t.src_ZPCc=[t.src_Z,t.src_P,t.src_Cc].join("|"),t.src_ZCc=[t.src_Z,t.src_Cc].join("|");return t.src_pseudo_letter="(?:(?![><|]|"+t.src_ZPCc+")"+t.src_Any+")",t.src_ip4="(?:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)",t.src_auth="(?:(?:(?!"+t.src_ZCc+"|[@/\\[\\]()]).)+@)?",t.src_port="(?::(?:6(?:[0-4]\\d{3}|5(?:[0-4]\\d{2}|5(?:[0-2]\\d|3[0-5])))|[1-5]?\\d{1,4}))?",t.src_host_terminator="(?=$|[><|]|"+t.src_ZPCc+")(?!-|_|:\\d|\\.-|\\.(?!$|"+t.src_ZPCc+"))",t.src_path="(?:[/?#](?:(?!"+t.src_ZCc+"|[><|]|[()[\\]{}.,\"'?!\\-]).|\\[(?:(?!"+t.src_ZCc+"|\\]).)*\\]|\\((?:(?!"+t.src_ZCc+"|[)]).)*\\)|\\{(?:(?!"+t.src_ZCc+'|[}]).)*\\}|\\"(?:(?!'+t.src_ZCc+'|["]).)+\\"|\\\'(?:(?!'+t.src_ZCc+"|[']).)+\\'|\\'(?="+t.src_pseudo_letter+"|[-]).|\\.{2,}[a-zA-Z0-9%/&]|\\.(?!"+t.src_ZCc+"|[.]).|"+(e&&e["---"]?"\\-(?!--(?:[^-]|$))(?:-*)|":"\\-+|")+"\\,(?!"+t.src_ZCc+").|\\!+(?!"+t.src_ZCc+"|[!]).|\\?(?!"+t.src_ZCc+"|[?]).)+|\\/)?",t.src_email_name='[\\-;:&=\\+\\$,\\.a-zA-Z0-9_][\\-;:&=\\+\\$,\\"\\.a-zA-Z0-9_]*',t.src_xn="xn--[a-z0-9\\-]{1,59}",t.src_domain_root="(?:"+t.src_xn+"|"+t.src_pseudo_letter+"{1,63})",t.src_domain="(?:"+t.src_xn+"|(?:"+t.src_pseudo_letter+")|(?:"+t.src_pseudo_letter+"(?:-|"+t.src_pseudo_letter+"){0,61}"+t.src_pseudo_letter+"))",t.src_host="(?:(?:(?:(?:"+t.src_domain+")\\.)*"+t.src_domain+"))",t.tpl_host_fuzzy="(?:"+t.src_ip4+"|(?:(?:(?:"+t.src_domain+")\\.)+(?:%TLDS%)))",t.tpl_host_no_ip_fuzzy="(?:(?:(?:"+t.src_domain+")\\.)+(?:%TLDS%))",t.src_host_strict=t.src_host+t.src_host_terminator,t.tpl_host_fuzzy_strict=t.tpl_host_fuzzy+t.src_host_terminator,t.src_host_port_strict=t.src_host+t.src_port+t.src_host_terminator,t.tpl_host_port_fuzzy_strict=t.tpl_host_fuzzy+t.src_port+t.src_host_terminator,t.tpl_host_port_no_ip_fuzzy_strict=t.tpl_host_no_ip_fuzzy+t.src_port+t.src_host_terminator,t.tpl_host_fuzzy_test="localhost|www\\.|\\.\\d{1,3}\\.|(?:\\.(?:%TLDS%)(?:"+t.src_ZPCc+"|>|$))",t.tpl_email_fuzzy='(^|[><|]|"|\\(|'+t.src_ZCc+")("+t.src_email_name+"@"+t.tpl_host_fuzzy_strict+")",t.tpl_link_fuzzy="(^|(?![.:/\\-_@])(?:[$+<=>^`||]|"+t.src_ZPCc+"))((?![$+<=>^`||])"+t.tpl_host_port_fuzzy_strict+t.src_path+")",t.tpl_link_no_ip_fuzzy="(^|(?![.:/\\-_@])(?:[$+<=>^`||]|"+t.src_ZPCc+"))((?![$+<=>^`||])"+t.tpl_host_port_no_ip_fuzzy_strict+t.src_path+")",t}},function(e,t){e.exports=/[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/},function(e,t){e.exports=/[\0-\x1F\x7F-\x9F]/},function(e,t){e.exports=/[ \xA0\u1680\u2000-\u200A\u202F\u205F\u3000]/},function(e,t){e.exports=/[!-#%-\*,-/:;\?@\[-\]_\{\}\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E44\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC9\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDC4B-\uDC4F\uDC5B\uDC5D\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDE60-\uDE6C\uDF3C-\uDF3E]|\uD807[\uDC41-\uDC45\uDC70\uDC71]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]|\uD83A[\uDD5E\uDD5F]/},function(e,t,r){(function(e,n){var s;/*! https://mths.be/punycode v1.4.1 by @mathias */!function(o){t&&t.nodeType,e&&e.nodeType;var i="object"==typeof n&&n;i.global!==i&&i.window!==i&&i.self;var a,u=2147483647,c=/^xn--/,l=/[^\x20-\x7E]/,p=/[\x2E\u3002\uFF0E\uFF61]/g,h={overflow:"Overflow: input needs wider integers to process","not-basic":"Illegal input >= 0x80 (not a basic code point)","invalid-input":"Invalid input"},f=Math.floor,d=String.fromCharCode;function m(e){throw new RangeError(h[e])}function g(e,t){for(var r=e.length,n=[];r--;)n[r]=t(e[r]);return n}function _(e,t){var r=e.split("@"),n="";return r.length>1&&(n=r[0]+"@",e=r[1]),n+g((e=e.replace(p,".")).split("."),t).join(".")}function b(e){for(var t,r,n=[],s=0,o=e.length;s=55296&&t<=56319&&s65535&&(t+=d((e-=65536)>>>10&1023|55296),e=56320|1023&e),t+=d(e)})).join("")}function C(e,t){return e+22+75*(e<26)-((0!=t)<<5)}function v(e,t,r){var n=0;for(e=r?f(e/700):e>>1,e+=f(e/t);e>455;n+=36)e=f(e/35);return f(n+36*e/(e+38))}function D(e){var t,r,n,s,o,i,a,c,l,p,h,d=[],g=e.length,_=0,b=128,C=72;for((r=e.lastIndexOf("-"))<0&&(r=0),n=0;n=128&&m("not-basic"),d.push(e.charCodeAt(n));for(s=r>0?r+1:0;s=g&&m("invalid-input"),((c=(h=e.charCodeAt(s++))-48<10?h-22:h-65<26?h-65:h-97<26?h-97:36)>=36||c>f((u-_)/i))&&m("overflow"),_+=c*i,!(c<(l=a<=C?1:a>=C+26?26:a-C));a+=36)i>f(u/(p=36-l))&&m("overflow"),i*=p;C=v(_-o,t=d.length+1,0==o),f(_/t)>u-b&&m("overflow"),b+=f(_/t),_%=t,d.splice(_++,0,b)}return k(d)}function A(e){var t,r,n,s,o,i,a,c,l,p,h,g,_,k,D,A=[];for(g=(e=b(e)).length,t=128,r=0,o=72,i=0;i=t&&hf((u-r)/(_=n+1))&&m("overflow"),r+=(a-t)*_,t=a,i=0;iu&&m("overflow"),h==t){for(c=r,l=36;!(c<(p=l<=o?1:l>=o+26?26:l-o));l+=36)D=c-p,k=36-p,A.push(d(C(p+D%k,0))),c=f(D/k);A.push(d(C(c,0))),o=v(r,_,n==s),r=0,++n}++r,++t}return A.join("")}a={version:"1.4.1",ucs2:{decode:b,encode:k},decode:D,encode:A,toASCII:function(e){return _(e,(function(e){return l.test(e)?"xn--"+A(e):e}))},toUnicode:function(e){return _(e,(function(e){return c.test(e)?D(e.slice(4).toLowerCase()):e}))}},void 0===(s=function(){return a}.call(t,r,t,e))||(e.exports=s)}()}).call(this,r(69)(e),r(70))},function(e,t){e.exports=function(e){return e.webpackPolyfill||(e.deprecate=function(){},e.paths=[],e.children||(e.children=[]),Object.defineProperty(e,"loaded",{enumerable:!0,get:function(){return e.l}}),Object.defineProperty(e,"id",{enumerable:!0,get:function(){return e.i}}),e.webpackPolyfill=1),e}},function(e,t){var r;r=function(){return this}();try{r=r||new Function("return this")()}catch(e){"object"==typeof window&&(r=window)}e.exports=r},function(e,t,r){"use strict";e.exports={options:{html:!1,xhtmlOut:!1,breaks:!1,langPrefix:"language-",linkify:!1,typographer:!1,quotes:"“”‘’",highlight:null,maxNesting:100},components:{core:{},block:{},inline:{}}}},function(e,t,r){"use strict";e.exports={options:{html:!1,xhtmlOut:!1,breaks:!1,langPrefix:"language-",linkify:!1,typographer:!1,quotes:"“”‘’",highlight:null,maxNesting:20},components:{core:{rules:["normalize","block","inline"]},block:{rules:["paragraph"]},inline:{rules:["text"],rules2:["balance_pairs","text_collapse"]}}}},function(e,t,r){"use strict";e.exports={options:{html:!0,xhtmlOut:!0,breaks:!1,langPrefix:"language-",linkify:!1,typographer:!1,quotes:"“”‘’",highlight:null,maxNesting:20},components:{core:{rules:["normalize","block","inline"]},block:{rules:["blockquote","code","fence","heading","hr","html_block","lheading","list","reference","paragraph"]},inline:{rules:["autolink","backticks","emphasis","entity","escape","html_inline","image","link","newline","text"],rules2:["balance_pairs","emphasis","text_collapse"]}}}}]); \ No newline at end of file diff --git a/extensions/markdown-language-features/notebook/index.ts b/extensions/markdown-language-features/notebook/index.ts index 035ff83ae15..1dcb131ae64 100644 --- a/extensions/markdown-language-features/notebook/index.ts +++ b/extensions/markdown-language-features/notebook/index.ts @@ -11,7 +11,9 @@ type extendMarkdownItFnType = ( ); (function () { - const markdownIt = new MarkdownIt(); + const markdownIt = new MarkdownIt({ + html: true + }); (globalThis as any).extendMarkdownIt = ((f: (md: MarkdownIt.MarkdownIt) => void) => { f(markdownIt); From 96718c6fe8c275d8dd778a8e2a54f6d557615ef8 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 11 Feb 2021 16:04:12 -0800 Subject: [PATCH 038/325] Add back build-notebook script --- extensions/markdown-language-features/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index cf7c8b291a0..8da6a42f808 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -322,11 +322,12 @@ ] }, "scripts": { - "compile": "gulp compile-extension:markdown-language-features && npm run build-preview", + "compile": "gulp compile-extension:markdown-language-features && npm run build-preview && npm run build-notebook", "watch": "npm run build-preview && gulp watch-extension:markdown-language-features", "vscode:prepublish": "npm run build-ext && npm run build-preview", "build-ext": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:markdown-language-features ./tsconfig.json", "build-preview": "npx webpack-cli --mode production", + "build-notebook": "npx webpack-cli --config webpack.notebook --mode production", "compile-web": "npx webpack-cli --config extension-browser.webpack.config --mode none", "watch-web": "npx webpack-cli --config extension-browser.webpack.config --mode none --watch --info-verbosity verbose" }, From 767dd7033df1480ce8e77e0be7d188b177f9f08c Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 11 Feb 2021 17:21:22 -0800 Subject: [PATCH 039/325] Try different workaround for rewriting localhost resources for remote webviews Fixes #102449 This tries using the webContentsId of the request instead of the `lastCommittedOrigin`. This will only work for electron based webviews. Iframe based webviews some additional frame metadata properties added in electron 12 --- .../webviewPortMappingProvider.ts | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/vs/platform/webview/electron-main/webviewPortMappingProvider.ts b/src/vs/platform/webview/electron-main/webviewPortMappingProvider.ts index da60a2bc507..f97a8bc0aae 100644 --- a/src/vs/platform/webview/electron-main/webviewPortMappingProvider.ts +++ b/src/vs/platform/webview/electron-main/webviewPortMappingProvider.ts @@ -3,8 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { OnBeforeRequestListenerDetails, session } from 'electron'; +import { OnBeforeRequestListenerDetails, session, webContents } from 'electron'; import { Disposable } from 'vs/base/common/lifecycle'; +import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; import { IAddress } from 'vs/platform/remote/common/remoteAgentConnection'; import { ITunnelService } from 'vs/platform/remote/common/tunnel'; @@ -21,12 +22,14 @@ interface PortMappingData { readonly resolvedAuthority: IAddress | null | undefined; } +interface WebviewData { + readonly manager: WebviewPortMappingManager; + readonly metadata: PortMappingData; +} + export class WebviewPortMappingProvider extends Disposable { - private readonly _webviewData = new Map(); + private readonly _webviewData = new Map(); constructor( @ITunnelService private readonly _tunnelService: ITunnelService, @@ -34,7 +37,6 @@ export class WebviewPortMappingProvider extends Disposable { super(); const sess = session.fromPartition(webviewPartitionId); - sess.webRequest.onBeforeRequest({ urls: [ '*://localhost:*/*', @@ -42,14 +44,26 @@ export class WebviewPortMappingProvider extends Disposable { '*://0.0.0.0:*/*', ] }, async (details: OnBeforeRequestListenerDetails_Extended, callback) => { - let origin: URI; + let webviewId: string | undefined; try { - origin = URI.parse(details.lastCommittedOrigin!); + if (details.lastCommittedOrigin) { + const origin = URI.parse(details.lastCommittedOrigin); + webviewId = origin.authority; + } else if (typeof details.webContentsId === 'number') { + const contents = webContents.fromId(details.webContentsId); + const url = URI.parse(contents.getURL()); + if (url.scheme === Schemas.vscodeWebview) { + webviewId = url.authority; + } + } } catch { return callback({}); } - const webviewId = origin.authority; + if (!webviewId) { + return callback({}); + } + const entry = this._webviewData.get(webviewId); if (!entry) { return callback({}); From 6ac9a3ecb3698e82bf901f11bbb5940f6bc3c197 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Thu, 11 Feb 2021 18:11:20 -0800 Subject: [PATCH 040/325] Add disable checkbox to getting started. Closes #114964. --- .../gettingStarted/browser/gettingStarted.css | 4 ++++ .../gettingStarted/browser/gettingStarted.ts | 17 ++++++++++++++++- .../contrib/welcome/page/browser/welcomePage.ts | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.css b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.css index 8b777cf64a7..5b4d1fcb93d 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.css +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.css @@ -330,3 +330,7 @@ text-decoration: underline; background: transparent; } + +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .showOnStartup { + text-align: center; +} diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts index f7c6019924c..cb7bcf8f3c9 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts @@ -26,8 +26,10 @@ import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Schemas } from 'vs/base/common/network'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; const SLIDE_TRANSITION_TIME_MS = 250; +const configurationKey = 'workbench.startupEditor'; export const gettingStartedInputTypeId = 'workbench.editors.gettingStartedInput'; @@ -89,6 +91,7 @@ export class GettingStartedPage extends EditorPane { @IProductService private readonly productService: IProductService, @IKeybindingService private readonly keybindingService: IKeybindingService, @IGettingStartedService private readonly gettingStartedService: IGettingStartedService, + @IConfigurationService private readonly configurationService: IConfigurationService, @ITelemetryService telemetryService: ITelemetryService, @IOpenerService private readonly openerService: IOpenerService, @IThemeService themeService: IThemeService, @@ -318,7 +321,19 @@ export class GettingStartedPage extends EditorPane { }); categoryScrollContainer.appendChild(categoriesContainer); - categoryScrollContainer.appendChild($('.footer', {}, $('button.skip.button-link', { 'x-dispatch': 'skip' }, localize('gettingStarted.skip', "Skip")))); + const showOnStartupCheckbox = $('input.checkbox', { id: 'showOnStartup', type: 'checkbox' }) as HTMLInputElement; + categoryScrollContainer.appendChild( + $('.footer', {}, + $('button.skip.button-link', { 'x-dispatch': 'skip' }, localize('gettingStarted.skip', "Skip")), + $('p.showOnStartup', {}, + showOnStartupCheckbox, + $('label.caption', { for: 'showOnStartup' }, localize('welcomePage.showOnStartup', "Show Getting Started page on startup"))) + )); + + showOnStartupCheckbox.checked = this.configurationService.getValue(configurationKey) === 'gettingStarted'; + this._register(addDisposableListener(showOnStartupCheckbox, 'click', () => { + this.configurationService.updateValue(configurationKey, showOnStartupCheckbox.checked ? 'gettingStarted' : 'welcomePage'); + })); if (this.categoriesScrollbar) { this.categoriesScrollbar.dispose(); } this.categoriesScrollbar = this._register(new DomScrollableElement(categoryScrollContainer, {})); diff --git a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts index 4952cefc6e8..fa02ee7ae2e 100644 --- a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts +++ b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts @@ -336,7 +336,7 @@ class WelcomePage extends Disposable { } private onReady(container: HTMLElement, recentlyOpened: Promise, installedExtensions: Promise): void { - const enabled = isWelcomePageEnabled(this.configurationService, this.contextService); + const enabled = this.configurationService.getValue(configurationKey) === 'welcomePage'; const showOnStartup = container.querySelector('#showOnStartup'); if (enabled) { showOnStartup.setAttribute('checked', 'checked'); From 795db5b71948cd494423b2c42a91d020d421979e Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 12 Feb 2021 08:09:13 +0100 Subject: [PATCH 041/325] Always intercept file protocol (#116522) * sandbox - intercept file protocol cc @deepak1556 * :lipstick: error messages --- src/vs/code/electron-main/protocol.ts | 44 ++++++++++++++++++--------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/src/vs/code/electron-main/protocol.ts b/src/vs/code/electron-main/protocol.ts index 5bfbebb680e..20644f2c9b9 100644 --- a/src/vs/code/electron-main/protocol.ts +++ b/src/vs/code/electron-main/protocol.ts @@ -37,19 +37,13 @@ export class FileProtocolHandler extends Disposable { // Register vscode-file:// handler defaultSession.protocol.registerFileProtocol(Schemas.vscodeFileResource, (request, callback) => this.handleResourceRequest(request, callback as unknown as ProtocolCallback)); - // Block any file:// access (explicitly enabled only) - if (isPreferringBrowserCodeLoad) { - this.logService.info(`Intercepting ${Schemas.file}: protocol and blocking it`); - - defaultSession.protocol.interceptFileProtocol(Schemas.file, (request, callback) => this.handleFileRequest(request, callback as unknown as ProtocolCallback)); - } + // Intercept any file:// access + defaultSession.protocol.interceptFileProtocol(Schemas.file, (request, callback) => this.handleFileRequest(request, callback as unknown as ProtocolCallback)); // Cleanup this._register(toDisposable(() => { defaultSession.protocol.unregisterProtocol(Schemas.vscodeFileResource); - if (isPreferringBrowserCodeLoad) { - defaultSession.protocol.uninterceptProtocol(Schemas.file); - } + defaultSession.protocol.uninterceptProtocol(Schemas.file); })); } @@ -85,10 +79,29 @@ export class FileProtocolHandler extends Disposable { } private async handleFileRequest(request: Electron.ProtocolRequest, callback: ProtocolCallback) { - const uri = URI.parse(request.url); + const fileUri = URI.parse(request.url); - this.logService.error(`Refused to load resource ${uri.fsPath} from ${Schemas.file}: protocol`); - callback({ error: -3 /* ABORTED */ }); + // isPreferringBrowserCodeLoad: false + // => ensure the file path is in our expected roots + if (!isPreferringBrowserCodeLoad) { + if (this.validRoots.findSubstr(fileUri)) { + return callback({ + path: fileUri.fsPath + }); + } + + this.logService.error(`${Schemas.file}: Refused to load resource ${fileUri.fsPath} from ${Schemas.file}: protocol (original URL: ${request.url})`); + + return callback({ error: -3 /* ABORTED */ }); + } + + // isPreferringBrowserCodeLoad: true + // => block any file request + else { + this.logService.error(`Refused to load resource ${fileUri.fsPath} from ${Schemas.file}: protocol (original URL: ${request.url})`); + + return callback({ error: -3 /* ABORTED */ }); + } } private async handleResourceRequest(request: Electron.ProtocolRequest, callback: ProtocolCallback) { @@ -102,9 +115,10 @@ export class FileProtocolHandler extends Disposable { return callback({ path: fileUri.fsPath }); - } + } else { + this.logService.error(`${Schemas.vscodeFileResource}: Refused to load resource ${fileUri.fsPath} from ${Schemas.vscodeFileResource}: protocol (original URL: ${request.url})`); - this.logService.error(`${Schemas.vscodeFileResource}: Refused to load resource ${fileUri.fsPath}}`); - callback({ error: -3 /* ABORTED */ }); + return callback({ error: -3 /* ABORTED */ }); + } } } From f0d62c6ec2db505188f670d1c577760d3dd718a2 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 12 Feb 2021 08:30:17 +0100 Subject: [PATCH 042/325] :lipstick: more main.ts cleanup --- src/vs/code/electron-main/main.ts | 84 ++++++++++--------- src/vs/code/node/cli.ts | 2 +- .../node/{waitMarkerFile.ts => wait.ts} | 9 +- 3 files changed, 47 insertions(+), 48 deletions(-) rename src/vs/platform/environment/node/{waitMarkerFile.ts => wait.ts} (72%) diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index 2201f7c0e50..0ccc3092bd4 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -10,7 +10,7 @@ import { localize } from 'vs/nls'; import { isWindows, IProcessEnvironment, isMacintosh } from 'vs/base/common/platform'; import product from 'vs/platform/product/common/product'; import { parseMainProcessArgv, addArg } from 'vs/platform/environment/node/argvHelper'; -import { createWaitMarkerFile } from 'vs/platform/environment/node/waitMarkerFile'; +import { createWaitMarkerFile } from 'vs/platform/environment/node/wait'; import { LifecycleMainService, ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc'; import { Server as NodeIPCServer, serve as nodeIPCServe, connect as nodeIPCConnect, XDG_RUNTIME_DIR } from 'vs/base/parts/ipc/node/ipc.net'; @@ -66,43 +66,22 @@ import { LoggerService } from 'vs/platform/log/node/loggerService'; class CodeMain { main(): void { + try { + this.startup(); + } catch (error) { + console.error(error.message); + app.exit(1); + } + } + + private async startup(): Promise { // Set the error handler early enough so that we are not getting the // default electron error dialog popping up setUnexpectedErrorHandler(err => console.error(err)); - // Parse arguments - let args: NativeParsedArgs; - try { - args = parseMainProcessArgv(process.argv); - args = this.validatePaths(args); - } catch (err) { - console.error(err.message); - app.exit(1); - - return; - } - - // If we are started with --wait create a random temporary file - // and pass it over to the starting instance. We can use this file - // to wait for it to be deleted to monitor that the edited file - // is closed and then exit the waiting process. - // - // Note: we are not doing this if the wait marker has been already - // added as argument. This can happen if Code was started from CLI. - if (args.wait && !args.waitMarkerFilePath) { - const waitMarkerFilePath = createWaitMarkerFile(args.verbose); - if (waitMarkerFilePath) { - addArg(process.argv, '--waitMarkerFilePath', waitMarkerFilePath); - args.waitMarkerFilePath = waitMarkerFilePath; - } - } - - // Launch - this.startup(args); - } - - private async startup(args: NativeParsedArgs): Promise { + // Resolve command line arguments + const args = this.resolveArgs(); // Create services const [instantiationService, instanceEnvironment, environmentService, configurationService, stateService, bufferLogService] = this.createServices(args); @@ -129,7 +108,7 @@ class CodeMain { // Create the main IPC server by trying to be the server // If this throws an error it means we are not the first // instance of VS Code running and so we would quit. - const mainIpcServer = await this.doStartup(args, logService, environmentService, lifecycleMainService, instantiationService, true); + const mainProcessNodeIpcServer = await this.doStartup(args, logService, environmentService, lifecycleMainService, instantiationService, true); // Delay creation of spdlog for perf reasons (https://github.com/microsoft/vscode/issues/72906) bufferLogService.logger = new SpdLogLogger('main', join(environmentService.logsPath, 'main.log'), true, bufferLogService.getLevel()); @@ -140,7 +119,7 @@ class CodeMain { configurationService.dispose(); }); - return instantiationService.createInstance(CodeApplication, mainIpcServer, instanceEnvironment).startup(); + return instantiationService.createInstance(CodeApplication, mainProcessNodeIpcServer, instanceEnvironment).startup(); }); } catch (error) { instantiationService.invokeFunction(this.quit, error); @@ -229,7 +208,7 @@ class CodeMain { environmentService.globalStorageHome.fsPath, environmentService.workspaceStorageHome.fsPath, environmentService.backupHome - ].map((path): undefined | Promise => path ? promises.mkdir(path, { recursive: true }) : undefined)); + ].map(path => path ? promises.mkdir(path, { recursive: true }) : undefined)); // Configuration service const configurationServiceInitialization = configurationService.initialize(); @@ -245,10 +224,10 @@ class CodeMain { // Try to setup a server for running. If that succeeds it means // we are the first instance to startup. Otherwise it is likely // that another instance is already running. - let server: NodeIPCServer; + let mainProcessNodeIpcServer: NodeIPCServer; try { - server = await nodeIPCServe(environmentService.mainIPCHandle); - once(lifecycleMainService.onWillShutdown)(() => server.dispose()); + mainProcessNodeIpcServer = await nodeIPCServe(environmentService.mainIPCHandle); + once(lifecycleMainService.onWillShutdown)(() => mainProcessNodeIpcServer.dispose()); } catch (error) { // Handle unexpected errors (the only expected error is EADDRINUSE that @@ -362,7 +341,7 @@ class CodeMain { // instance to startup. Otherwise we would wrongly overwrite the PID process.env['VSCODE_PID'] = String(process.pid); - return server; + return mainProcessNodeIpcServer; } private handleStartupDataDirError(environmentService: IEnvironmentMainService, error: NodeJS.ErrnoException): void { @@ -429,7 +408,30 @@ class CodeMain { lifecycleMainService.kill(exitCode); } - //#region Path Helpers + //#region Command line arguments utilities + + private resolveArgs(): NativeParsedArgs { + + // Parse arguments + const args = this.validatePaths(parseMainProcessArgv(process.argv)); + + // If we are started with --wait create a random temporary file + // and pass it over to the starting instance. We can use this file + // to wait for it to be deleted to monitor that the edited file + // is closed and then exit the waiting process. + // + // Note: we are not doing this if the wait marker has been already + // added as argument. This can happen if Code was started from CLI. + if (args.wait && !args.waitMarkerFilePath) { + const waitMarkerFilePath = createWaitMarkerFile(args.verbose); + if (waitMarkerFilePath) { + addArg(process.argv, '--waitMarkerFilePath', waitMarkerFilePath); + args.waitMarkerFilePath = waitMarkerFilePath; + } + } + + return args; + } private validatePaths(args: NativeParsedArgs): NativeParsedArgs { diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index ac557018989..43f8ea01331 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -9,7 +9,7 @@ import { spawn, ChildProcess, SpawnOptions } from 'child_process'; import { buildHelpMessage, buildVersionMessage, OPTIONS } from 'vs/platform/environment/node/argv'; import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; import { parseCLIProcessArgv, addArg } from 'vs/platform/environment/node/argvHelper'; -import { createWaitMarkerFile } from 'vs/platform/environment/node/waitMarkerFile'; +import { createWaitMarkerFile } from 'vs/platform/environment/node/wait'; import product from 'vs/platform/product/common/product'; import { isAbsolute, join } from 'vs/base/common/path'; import { whenDeleted, writeFileSync } from 'vs/base/node/pfs'; diff --git a/src/vs/platform/environment/node/waitMarkerFile.ts b/src/vs/platform/environment/node/wait.ts similarity index 72% rename from src/vs/platform/environment/node/waitMarkerFile.ts rename to src/vs/platform/environment/node/wait.ts index 8916ef40732..9441f808590 100644 --- a/src/vs/platform/environment/node/waitMarkerFile.ts +++ b/src/vs/platform/environment/node/wait.ts @@ -3,15 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -/** - * This code is also used by standalone cli's. Avoid adding dependencies to keep the size of the cli small. - */ -import * as path from 'vs/base/common/path'; -import * as os from 'os'; import * as fs from 'fs'; +import { tmpdir } from 'os'; +import { join } from 'vs/base/common/path'; export function createWaitMarkerFile(verbose?: boolean): string | undefined { - const randomWaitMarkerPath = path.join(os.tmpdir(), Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 10)); + const randomWaitMarkerPath = join(tmpdir(), Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 10)); try { fs.writeFileSync(randomWaitMarkerPath, ''); // use built-in fs to avoid dragging in more dependencies From 2911d1d1dd6367262fbc428d4394740c967f8b7c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 12 Feb 2021 09:22:28 +0100 Subject: [PATCH 043/325] setting editable metadata --- .vscode/notebooks/inbox.github-issues | 9 +++------ .vscode/notebooks/my-work.github-issues | 27 +++++++++---------------- 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/.vscode/notebooks/inbox.github-issues b/.vscode/notebooks/inbox.github-issues index c7134b3a289..f14b59f1483 100644 --- a/.vscode/notebooks/inbox.github-issues +++ b/.vscode/notebooks/inbox.github-issues @@ -8,8 +8,7 @@ { "kind": 2, "language": "github-issues", - "value": "$inbox -label:\"needs more info\"", - "editable": true + "value": "$inbox -label:\"needs more info\"" }, { "kind": 1, @@ -20,8 +19,7 @@ { "kind": 2, "language": "github-issues", - "value": "$inbox=repo:microsoft/vscode is:open no:assignee -label:feature-request -label:testplan-item -label:plan-item ", - "editable": true + "value": "$inbox=repo:microsoft/vscode is:open no:assignee -label:feature-request -label:testplan-item -label:plan-item " }, { "kind": 1, @@ -44,7 +42,6 @@ { "kind": 2, "language": "github-issues", - "value": "$inbox", - "editable": true + "value": "$inbox" } ] \ No newline at end of file diff --git a/.vscode/notebooks/my-work.github-issues b/.vscode/notebooks/my-work.github-issues index a566e7309fa..fb59e914e78 100644 --- a/.vscode/notebooks/my-work.github-issues +++ b/.vscode/notebooks/my-work.github-issues @@ -8,8 +8,7 @@ { "kind": 2, "language": "github-issues", - "value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog\n\n// current milestone name\n$milestone=milestone:\"February 2021\"", - "editable": true + "value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog\n\n// current milestone name\n$milestone=milestone:\"February 2021\"" }, { "kind": 1, @@ -20,8 +19,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repos $milestone assignee:@me is:open", - "editable": false + "value": "$repos $milestone assignee:@me is:open" }, { "kind": 1, @@ -38,8 +36,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open label:bug", - "editable": true + "value": "$repos assignee:@me is:open label:bug" }, { "kind": 1, @@ -50,8 +47,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open label:debt OR $repos assignee:@me is:open label:engineering", - "editable": true + "value": "$repos assignee:@me is:open label:debt OR $repos assignee:@me is:open label:engineering" }, { "kind": 1, @@ -62,8 +58,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open label:perf OR $repos assignee:@me is:open label:perf-startup OR $repos assignee:@me is:open label:perf-bloat OR $repos assignee:@me is:open label:freeze-slow-crash-leak", - "editable": true + "value": "$repos assignee:@me is:open label:perf OR $repos assignee:@me is:open label:perf-startup OR $repos assignee:@me is:open label:perf-bloat OR $repos assignee:@me is:open label:freeze-slow-crash-leak" }, { "kind": 1, @@ -74,14 +69,12 @@ { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open label:feature-request milestone:Backlog sort:reactions-+1-desc", - "editable": true + "value": "$repos assignee:@me is:open label:feature-request milestone:Backlog sort:reactions-+1-desc" }, { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open milestone:\"Backlog Candidates\"", - "editable": false + "value": "$repos assignee:@me is:open milestone:\"Backlog Candidates\"" }, { "kind": 1, @@ -98,8 +91,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open type:issue -label:bug -label:\"needs more info\" -label:feature-request -label:under-discussion -label:debt -label:plan-item -label:upstream", - "editable": true + "value": "$repos assignee:@me is:open type:issue -label:bug -label:\"needs more info\" -label:feature-request -label:under-discussion -label:debt -label:plan-item -label:upstream" }, { "kind": 1, @@ -110,7 +102,6 @@ { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open label:\"needs more info\"", - "editable": false + "value": "$repos assignee:@me is:open label:\"needs more info\"" } ] \ No newline at end of file From ed10bfb7c4f8856c80d737a0ade60b8bea4ca18f Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 12 Feb 2021 09:28:46 +0100 Subject: [PATCH 044/325] update tsec to 0.1.3 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index cee4950e77e..cc9f055cc99 100644 --- a/package.json +++ b/package.json @@ -189,7 +189,7 @@ "source-map-support": "^0.3.2", "style-loader": "^1.0.0", "ts-loader": "^6.2.1", - "tsec": "0.1.1", + "tsec": "0.1.3", "typescript": "4.2.0-dev.20201207", "typescript-formatter": "7.1.0", "underscore": "^1.8.2", diff --git a/yarn.lock b/yarn.lock index b8177d34186..8695942fcec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9596,10 +9596,10 @@ ts-morph@^3.1.3: multimatch "^4.0.0" typescript "^3.0.1" -tsec@0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/tsec/-/tsec-0.1.1.tgz#aed25d4aeea0d1f641d4c941c3da23db1a7d1ce2" - integrity sha512-hAQJlm4SXO5c8//rWNdIwa8CX9wcXeyxo0S+D5pgU+m88LEbXqd+FGyVaysbfnVf6yywpQFte3dpXaudOl+NeQ== +tsec@0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/tsec/-/tsec-0.1.3.tgz#e3bc072c3307ba532c45efc8050d5eb8d52dadee" + integrity sha512-ek9ga1ZHFpLb96ydHQXgsAlgk2uEiVswmwyGNGuMakl2KFnJqLa2zvG7Qqxoo1PhSooyY7WNP1cgSYzgWTHetg== dependencies: glob "^7.1.1" From b06c9c66f56f7e8cc1ccafb54591b425d50c3ed6 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 12 Feb 2021 09:32:15 +0100 Subject: [PATCH 045/325] :up: distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cc9f055cc99..3b0ce899f1c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.54.0", - "distro": "4e0b11c36e1bc4032ef3c28c82fdf336f7f48cf3", + "distro": "59d93479b4a5c88173a91fec50e348126e94a818", "author": { "name": "Microsoft Corporation" }, From 968ce642c3c059b8538843bf79a68de0e8a94822 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 12 Feb 2021 10:04:27 +0100 Subject: [PATCH 046/325] add tsec to CI, https://github.com/microsoft/vscode/issues/116459 --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 73acbb00426..d53283f0cf4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -247,6 +247,9 @@ jobs: - name: Run Monaco Editor Checks run: yarn monaco-compile-check + - name: Run Trusted Types Checks + run: yarn tsec-compile-check + - name: Editor Distro & ESM Bundle run: yarn gulp editor-esm-bundle From 868fb4c39f3e07899d7e88317510fcdab13b2849 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 12 Feb 2021 10:25:12 +0100 Subject: [PATCH 047/325] rename CellKind to NotebookCellKind --- .../src/notebook.test.ts | 18 ++++++------- .../src/notebookSmokeTestMain.ts | 4 +-- .../src/notebookTestMain.ts | 2 +- src/vs/vscode.proposed.d.ts | 6 ++--- .../workbench/api/common/extHost.api.impl.ts | 4 +-- .../common/extHostNotebookConcatDocument.ts | 3 +-- .../api/common/extHostNotebookDocument.ts | 2 +- .../api/common/extHostTypeConverters.ts | 26 +++++++++++++++++-- src/vs/workbench/api/common/extHostTypes.ts | 2 +- 9 files changed, 44 insertions(+), 23 deletions(-) diff --git a/extensions/vscode-notebook-tests/src/notebook.test.ts b/extensions/vscode-notebook-tests/src/notebook.test.ts index ad15fd0a3eb..0117e41160a 100644 --- a/extensions/vscode-notebook-tests/src/notebook.test.ts +++ b/extensions/vscode-notebook-tests/src/notebook.test.ts @@ -418,7 +418,7 @@ suite('Notebook API tests', () => { const cellsChangeEvent = getEventOncePromise(vscode.notebook.onDidChangeNotebookCells); await vscode.window.activeNotebookEditor!.edit(editBuilder => { - editBuilder.replaceCells(1, 0, [{ cellKind: vscode.CellKind.Code, language: 'javascript', source: 'test 2', outputs: [], metadata: undefined }]); + editBuilder.replaceCells(1, 0, [{ cellKind: vscode.NotebookCellKind.Code, language: 'javascript', source: 'test 2', outputs: [], metadata: undefined }]); }); const cellChangeEventRet = await cellsChangeEvent; @@ -561,13 +561,13 @@ suite('Notebook API tests', () => { { const edit = new vscode.WorkspaceEdit(); edit.replaceNotebookCells(document.uri, 0, 0, [{ - cellKind: vscode.CellKind.Markdown, + cellKind: vscode.NotebookCellKind.Markdown, language: 'markdown', metadata: undefined, outputs: [], source: 'new_markdown' }, { - cellKind: vscode.CellKind.Code, + cellKind: vscode.NotebookCellKind.Code, language: 'fooLang', metadata: undefined, outputs: [], @@ -598,13 +598,13 @@ suite('Notebook API tests', () => { { const edit = new vscode.WorkspaceEdit(); edit.replaceNotebookCells(document.uri, 0, 1, [{ - cellKind: vscode.CellKind.Markdown, + cellKind: vscode.NotebookCellKind.Markdown, language: 'markdown', metadata: undefined, outputs: [], source: 'new2_markdown' }, { - cellKind: vscode.CellKind.Code, + cellKind: vscode.NotebookCellKind.Code, language: 'fooLang', metadata: undefined, outputs: [], @@ -640,13 +640,13 @@ suite('Notebook API tests', () => { const edit = new vscode.WorkspaceEdit(); edit.replaceNotebookCells(document.uri, 0, 0, [{ - cellKind: vscode.CellKind.Markdown, + cellKind: vscode.NotebookCellKind.Markdown, language: 'markdown', metadata: undefined, outputs: [], source: 'new_markdown' }, { - cellKind: vscode.CellKind.Code, + cellKind: vscode.NotebookCellKind.Code, language: 'fooLang', metadata: undefined, outputs: [], @@ -685,7 +685,7 @@ suite('Notebook API tests', () => { const cellMetadataChangeEvent = getEventOncePromise(vscode.notebook.onDidChangeCellMetadata); const version = vscode.window.activeNotebookEditor!.document.version; await vscode.window.activeNotebookEditor!.edit(editBuilder => { - editBuilder.replaceCells(1, 0, [{ cellKind: vscode.CellKind.Code, language: 'javascript', source: 'test 2', outputs: [], metadata: undefined }]); + editBuilder.replaceCells(1, 0, [{ cellKind: vscode.NotebookCellKind.Code, language: 'javascript', source: 'test 2', outputs: [], metadata: undefined }]); editBuilder.replaceCellMetadata(0, { runnable: false }); }); @@ -704,7 +704,7 @@ suite('Notebook API tests', () => { const cellMetadataChangeEvent = getEventOncePromise(vscode.notebook.onDidChangeCellMetadata); const version = vscode.window.activeNotebookEditor!.document.version; await vscode.window.activeNotebookEditor!.edit(editBuilder => { - editBuilder.replaceCells(1, 0, [{ cellKind: vscode.CellKind.Code, language: 'javascript', source: 'test 2', outputs: [], metadata: undefined }]); + editBuilder.replaceCells(1, 0, [{ cellKind: vscode.NotebookCellKind.Code, language: 'javascript', source: 'test 2', outputs: [], metadata: undefined }]); editBuilder.replaceCellMetadata(0, { runnable: false }); }); diff --git a/extensions/vscode-notebook-tests/src/notebookSmokeTestMain.ts b/extensions/vscode-notebook-tests/src/notebookSmokeTestMain.ts index 78a201526fc..0e3e7426f23 100644 --- a/extensions/vscode-notebook-tests/src/notebookSmokeTestMain.ts +++ b/extensions/vscode-notebook-tests/src/notebookSmokeTestMain.ts @@ -28,7 +28,7 @@ export function smokeTestActivate(context: vscode.ExtensionContext): any { { source: 'code()', language: 'typescript', - cellKind: vscode.CellKind.Code, + cellKind: vscode.NotebookCellKind.Code, outputs: [], metadata: { custom: { testCellMetadata: 123 } @@ -37,7 +37,7 @@ export function smokeTestActivate(context: vscode.ExtensionContext): any { { source: 'Markdown Cell', language: 'markdown', - cellKind: vscode.CellKind.Markdown, + cellKind: vscode.NotebookCellKind.Markdown, outputs: [], metadata: { custom: { testCellMetadata: 123 } diff --git a/extensions/vscode-notebook-tests/src/notebookTestMain.ts b/extensions/vscode-notebook-tests/src/notebookTestMain.ts index ef3c477d6e5..c856d19e46c 100644 --- a/extensions/vscode-notebook-tests/src/notebookTestMain.ts +++ b/extensions/vscode-notebook-tests/src/notebookTestMain.ts @@ -26,7 +26,7 @@ export function activate(context: vscode.ExtensionContext): any { { source: 'test', language: 'typescript', - cellKind: vscode.CellKind.Code, + cellKind: vscode.NotebookCellKind.Code, outputs: [], metadata: { custom: { testCellMetadata: 123 } diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 9fea737d5a0..febf42232e6 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1000,7 +1000,7 @@ declare module 'vscode' { //#region https://github.com/microsoft/vscode/issues/106744, Notebooks (misc) - export enum CellKind { + export enum NotebookCellKind { Markdown = 1, Code = 2 } @@ -1052,7 +1052,7 @@ declare module 'vscode' { readonly index: number; readonly notebook: NotebookDocument; readonly uri: Uri; - readonly cellKind: CellKind; + readonly cellKind: NotebookCellKind; readonly document: TextDocument; readonly language: string; readonly outputs: readonly NotebookCellOutput[]; @@ -1248,7 +1248,7 @@ declare module 'vscode' { // todo@API support ids https://github.com/jupyter/enhancement-proposals/blob/master/62-cell-id/cell-id.md export interface NotebookCellData { - readonly cellKind: CellKind; + readonly cellKind: NotebookCellKind; readonly source: string; readonly language: string; // todo@API maybe use a separate data type? diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 51c3ad42cfa..09a44ef2b07 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -1253,9 +1253,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I // checkProposedApiEnabled(extension); return extHostTypes.TimelineItem; }, - get CellKind() { + get NotebookCellKind() { // checkProposedApiEnabled(extension); - return extHostTypes.CellKind; + return extHostTypes.NotebookCellKind; }, get NotebookCellRunState() { // checkProposedApiEnabled(extension); diff --git a/src/vs/workbench/api/common/extHostNotebookConcatDocument.ts b/src/vs/workbench/api/common/extHostNotebookConcatDocument.ts index 4702e1c8165..6b1fb1f5e95 100644 --- a/src/vs/workbench/api/common/extHostNotebookConcatDocument.ts +++ b/src/vs/workbench/api/common/extHostNotebookConcatDocument.ts @@ -11,7 +11,6 @@ import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { score } from 'vs/editor/common/modes/languageSelector'; -import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { ResourceMap } from 'vs/base/common/map'; import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; @@ -76,7 +75,7 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD const cellLengths: number[] = []; const cellLineCounts: number[] = []; for (const cell of this._notebook.cells) { - if (cell.cellKind === CellKind.Code && (!this._selector || score(this._selector, cell.uri, cell.language, true))) { + if (cell.cellKind === types.NotebookCellKind.Code && (!this._selector || score(this._selector, cell.uri, cell.language, true))) { this._cellUris.set(cell.uri, this._cells.length); this._cells.push(cell); cellLengths.push(cell.document.getText().length + 1); diff --git a/src/vs/workbench/api/common/extHostNotebookDocument.ts b/src/vs/workbench/api/common/extHostNotebookDocument.ts index 053edfad772..21d2e99a563 100644 --- a/src/vs/workbench/api/common/extHostNotebookDocument.ts +++ b/src/vs/workbench/api/common/extHostNotebookDocument.ts @@ -88,7 +88,7 @@ export class ExtHostCell extends Disposable { get index() { return that._notebook.getCellIndex(that); }, notebook: that._notebook.notebookDocument, uri: that.uri, - cellKind: this._cellData.cellKind, + cellKind: extHostTypeConverters.NotebookCellKind.to(this._cellData.cellKind), document: data.document, get language() { return data!.document.languageId; }, get outputs() { return that._outputs.map(extHostTypeConverters.NotebookCellOutput.to); }, diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 5f211700488..9799bddf7bd 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -31,7 +31,7 @@ import { coalesce, isNonEmptyArray } from 'vs/base/common/arrays'; import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions'; import { CommandsConverter } from 'vs/workbench/api/common/extHostCommands'; import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook'; -import { CellEditType, ICellDto2, INotebookDecorationRenderOptions, IOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellEditType, CellKind, ICellDto2, INotebookDecorationRenderOptions, IOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { ITestItem, ITestState } from 'vs/workbench/contrib/testing/common/testCollection'; export interface PositionLike { @@ -1344,11 +1344,33 @@ export namespace LanguageSelector { } } +export namespace NotebookCellKind { + export function from(data: vscode.NotebookCellKind): CellKind { + switch (data) { + case types.NotebookCellKind.Markdown: + return CellKind.Markdown; + case types.NotebookCellKind.Code: + default: + return CellKind.Code; + } + } + + export function to(data: CellKind): vscode.NotebookCellKind { + switch (data) { + case CellKind.Markdown: + return types.NotebookCellKind.Markdown; + case CellKind.Code: + default: + return types.NotebookCellKind.Code; + } + } +} + export namespace NotebookCellData { export function from(data: vscode.NotebookCellData): ICellDto2 { return { - cellKind: data.cellKind, + cellKind: NotebookCellKind.from(data.cellKind), language: data.language, source: data.source, metadata: data.metadata, diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 1afc1dceed4..96a66824ee6 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -2933,7 +2933,7 @@ export class NotebookCellOutput { ) { } } -export enum CellKind { +export enum NotebookCellKind { Markdown = 1, Code = 2 } From 6d9611747ea032060ec3733bc295e01a6f4b0ca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Fri, 12 Feb 2021 11:01:57 +0100 Subject: [PATCH 048/325] wip: update list ux - focus is now outline - expanding folders on twistie click only - clicking twistie now sets focus - list empty selection outline matches focus outline --- src/vs/base/browser/ui/list/listWidget.ts | 7 +++- src/vs/base/browser/ui/tree/abstractTree.ts | 3 +- src/vs/base/browser/ui/tree/media/tree.css | 4 ++ src/vs/platform/list/browser/listService.ts | 2 +- src/vs/platform/theme/common/colorRegistry.ts | 5 ++- src/vs/platform/theme/common/styler.ts | 39 ++++++++++--------- 6 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 81caae42707..398ace4b213 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -776,7 +776,11 @@ export class DefaultStyleController implements IStyleController { } if (styles.listHoverBackground) { - content.push(`.monaco-list${suffix}:not(.drop-target) .monaco-list-row:hover:not(.selected):not(.focused) { background-color: ${styles.listHoverBackground}; }`); + content.push(`.monaco-list${suffix}:not(.drop-target) .monaco-list-row:hover:not(.selected):not(.focused) { background-color: ${styles.listHoverBackground}; }`); + } + + if (styles.listTwistieHoverBackground) { + content.push(`.monaco-list${suffix}:not(.drop-target) .monaco-tl-twistie:hover::before { background-color: ${styles.listTwistieHoverBackground}; }`); } if (styles.listHoverForeground) { @@ -870,6 +874,7 @@ export interface IListStyles { listInactiveFocusBackground?: Color; listHoverBackground?: Color; listHoverForeground?: Color; + listTwistieHoverBackground?: Color; listDropBackground?: Color; listFocusOutline?: Color; listInactiveFocusOutline?: Color; diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index 4df19745cfe..3e135b3c8a8 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -1129,6 +1129,7 @@ class TreeNodeListMouseController extends MouseController< const model = ((this.tree as any).model as ITreeModel); // internal const location = model.getNodeLocation(node); const recursive = e.browserEvent.altKey; + this.tree.setFocus([location]); model.setCollapsed(location, undefined, recursive); if (expandOnlyOnTwistieClick && onTwistie) { @@ -1263,7 +1264,7 @@ export abstract class AbstractTree implements IDisposable get onDidChangeTypeFilterPattern(): Event { return this.typeFilterController ? this.typeFilterController.onDidChangePattern : Event.None; } get expandOnlyOnDoubleClick(): boolean { return this._options.expandOnlyOnDoubleClick ?? false; } - get expandOnlyOnTwistieClick(): boolean | ((e: T) => boolean) { return typeof this._options.expandOnlyOnTwistieClick === 'undefined' ? false : this._options.expandOnlyOnTwistieClick; } + get expandOnlyOnTwistieClick(): boolean | ((e: T) => boolean) { return typeof this._options.expandOnlyOnTwistieClick === 'undefined' ? true : this._options.expandOnlyOnTwistieClick; } private readonly _onDidUpdateOptions = new Emitter>(); readonly onDidUpdateOptions: Event> = this._onDidUpdateOptions.event; diff --git a/src/vs/base/browser/ui/tree/media/tree.css b/src/vs/base/browser/ui/tree/media/tree.css index 06f775d6246..2701b559d5e 100644 --- a/src/vs/base/browser/ui/tree/media/tree.css +++ b/src/vs/base/browser/ui/tree/media/tree.css @@ -56,6 +56,10 @@ overflow: hidden; } +.monaco-tl-twistie::before { + border-radius: 20px; +} + .monaco-tl-twistie.collapsed::before { transform: rotate(-90deg); } diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index 1d515e5bf6a..127f5ad81bf 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -1065,7 +1065,7 @@ configurationRegistry.registerConfiguration({ [treeExpandMode]: { type: 'string', enum: ['singleClick', 'doubleClick'], - default: 'singleClick', + default: 'doubleClick', description: localize('expand mode', "Controls how tree folders are expanded when clicking the folder names."), } } diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index 1256437a0d7..8ed02eb2756 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -362,15 +362,18 @@ export const diffDiagonalFill = registerColor('diffEditor.diagonalFill', { dark: /** * List and tree colors */ -export const listFocusBackground = registerColor('list.focusBackground', { dark: '#062F4A', light: '#D6EBFF', hc: null }, nls.localize('listFocusBackground', "List/Tree background color for the focused item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.")); +export const listFocusBackground = registerColor('list.focusBackground', { dark: null, light: null, hc: null }, nls.localize('listFocusBackground', "List/Tree background color for the focused item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.")); export const listFocusForeground = registerColor('list.focusForeground', { dark: null, light: null, hc: null }, nls.localize('listFocusForeground', "List/Tree foreground color for the focused item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.")); +export const listFocusOutline = registerColor('list.focusOutline', { dark: focusBorder, light: focusBorder, hc: activeContrastBorder }, nls.localize('listFocusOutline', "List/Tree outline color for the focused item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.")); export const listActiveSelectionBackground = registerColor('list.activeSelectionBackground', { dark: '#094771', light: '#0060C0', hc: null }, nls.localize('listActiveSelectionBackground', "List/Tree background color for the selected item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.")); export const listActiveSelectionForeground = registerColor('list.activeSelectionForeground', { dark: Color.white, light: Color.white, hc: null }, nls.localize('listActiveSelectionForeground', "List/Tree foreground color for the selected item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.")); export const listInactiveSelectionBackground = registerColor('list.inactiveSelectionBackground', { dark: '#37373D', light: '#E4E6F1', hc: null }, nls.localize('listInactiveSelectionBackground', "List/Tree background color for the selected item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.")); export const listInactiveSelectionForeground = registerColor('list.inactiveSelectionForeground', { dark: null, light: null, hc: null }, nls.localize('listInactiveSelectionForeground', "List/Tree foreground color for the selected item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.")); export const listInactiveFocusBackground = registerColor('list.inactiveFocusBackground', { dark: null, light: null, hc: null }, nls.localize('listInactiveFocusBackground', "List/Tree background color for the focused item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.")); +export const listInactiveFocusOutline = registerColor('list.inactiveFocusOutline', { dark: null, light: null, hc: null }, nls.localize('listInactiveFocusOutline', "List/Tree outline color for the focused item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.")); export const listHoverBackground = registerColor('list.hoverBackground', { dark: '#2A2D2E', light: '#F0F0F0', hc: null }, nls.localize('listHoverBackground', "List/Tree background when hovering over items using the mouse.")); export const listHoverForeground = registerColor('list.hoverForeground', { dark: null, light: null, hc: null }, nls.localize('listHoverForeground', "List/Tree foreground when hovering over items using the mouse.")); +export const listTwistieHoverBackground = registerColor('list.twistieHoverBackground', { dark: transparent(lighten(listHoverBackground, 0.5), 0.7), light: transparent(darken(listHoverBackground, 0.1), 0.7), hc: null }, nls.localize('twistieHoverBackground', "List/Tree background when hovering over a twistie using the mouse.")); export const listDropBackground = registerColor('list.dropBackground', { dark: listFocusBackground, light: listFocusBackground, hc: null }, nls.localize('listDropBackground', "List/Tree drag and drop background when moving items around using the mouse.")); export const listHighlightForeground = registerColor('list.highlightForeground', { dark: '#0097fb', light: '#0066BF', hc: focusBorder }, nls.localize('highlight', 'List/Tree foreground color of the match highlights when searching inside the list/tree.')); export const listInvalidItemForeground = registerColor('list.invalidItemForeground', { dark: '#B89500', light: '#B89500', hc: '#B89500' }, nls.localize('invalidItemForeground', 'List/Tree foreground color for invalid items, for example an unresolved root in explorer.')); diff --git a/src/vs/platform/theme/common/styler.ts b/src/vs/platform/theme/common/styler.ts index 90bb201972c..68d7d175e40 100644 --- a/src/vs/platform/theme/common/styler.ts +++ b/src/vs/platform/theme/common/styler.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService'; -import { focusBorder, inputBackground, inputForeground, ColorIdentifier, selectForeground, selectBackground, selectListBackground, selectBorder, inputBorder, foreground, editorBackground, contrastBorder, inputActiveOptionBorder, inputActiveOptionBackground, inputActiveOptionForeground, listFocusBackground, listFocusForeground, listActiveSelectionBackground, listActiveSelectionForeground, listInactiveSelectionForeground, listInactiveSelectionBackground, listInactiveFocusBackground, listHoverBackground, listHoverForeground, listDropBackground, pickerGroupBorder, pickerGroupForeground, widgetShadow, inputValidationInfoBorder, inputValidationInfoBackground, inputValidationWarningBorder, inputValidationWarningBackground, inputValidationErrorBorder, inputValidationErrorBackground, activeContrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, ColorFunction, badgeBackground, badgeForeground, progressBarBackground, breadcrumbsForeground, breadcrumbsFocusForeground, breadcrumbsActiveSelectionForeground, breadcrumbsBackground, editorWidgetBorder, inputValidationInfoForeground, inputValidationWarningForeground, inputValidationErrorForeground, menuForeground, menuBackground, menuSelectionForeground, menuSelectionBackground, menuSelectionBorder, menuBorder, menuSeparatorBackground, darken, listFilterWidgetOutline, listFilterWidgetNoMatchesOutline, listFilterWidgetBackground, editorWidgetBackground, treeIndentGuidesStroke, editorWidgetForeground, simpleCheckboxBackground, simpleCheckboxBorder, simpleCheckboxForeground, ColorValue, resolveColorValue, textLinkForeground, problemsWarningIconForeground, problemsErrorIconForeground, problemsInfoIconForeground, buttonSecondaryBackground, buttonSecondaryForeground, buttonSecondaryHoverBackground } from 'vs/platform/theme/common/colorRegistry'; +import { focusBorder, inputBackground, inputForeground, ColorIdentifier, selectForeground, selectBackground, selectListBackground, selectBorder, inputBorder, foreground, editorBackground, contrastBorder, inputActiveOptionBorder, inputActiveOptionBackground, inputActiveOptionForeground, listFocusBackground, listFocusForeground, listActiveSelectionBackground, listActiveSelectionForeground, listInactiveSelectionForeground, listInactiveSelectionBackground, listInactiveFocusBackground, listHoverBackground, listHoverForeground, listTwistieHoverBackground, listDropBackground, pickerGroupBorder, pickerGroupForeground, widgetShadow, inputValidationInfoBorder, inputValidationInfoBackground, inputValidationWarningBorder, inputValidationWarningBackground, inputValidationErrorBorder, inputValidationErrorBackground, activeContrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, ColorFunction, badgeBackground, badgeForeground, progressBarBackground, breadcrumbsForeground, breadcrumbsFocusForeground, breadcrumbsActiveSelectionForeground, breadcrumbsBackground, editorWidgetBorder, inputValidationInfoForeground, inputValidationWarningForeground, inputValidationErrorForeground, menuForeground, menuBackground, menuSelectionForeground, menuSelectionBackground, menuSelectionBorder, menuBorder, menuSeparatorBackground, darken, listFilterWidgetOutline, listFilterWidgetNoMatchesOutline, listFilterWidgetBackground, editorWidgetBackground, treeIndentGuidesStroke, editorWidgetForeground, simpleCheckboxBackground, simpleCheckboxBorder, simpleCheckboxForeground, ColorValue, resolveColorValue, textLinkForeground, problemsWarningIconForeground, problemsErrorIconForeground, problemsInfoIconForeground, buttonSecondaryBackground, buttonSecondaryForeground, buttonSecondaryHoverBackground, listFocusOutline, listInactiveFocusOutline } from 'vs/platform/theme/common/colorRegistry'; import { IDisposable } from 'vs/base/common/lifecycle'; import { Color } from 'vs/base/common/color'; import { IThemable, styleFn } from 'vs/base/common/styler'; @@ -210,6 +210,7 @@ export interface IListStyleOverrides extends IStyleOverrides { listBackground?: ColorIdentifier; listFocusBackground?: ColorIdentifier; listFocusForeground?: ColorIdentifier; + listFocusOutline?: ColorIdentifier; listActiveSelectionBackground?: ColorIdentifier; listActiveSelectionForeground?: ColorIdentifier; listFocusAndSelectionBackground?: ColorIdentifier; @@ -217,11 +218,11 @@ export interface IListStyleOverrides extends IStyleOverrides { listInactiveSelectionBackground?: ColorIdentifier; listInactiveSelectionForeground?: ColorIdentifier; listInactiveFocusBackground?: ColorIdentifier; + listInactiveFocusOutline?: ColorIdentifier; listHoverBackground?: ColorIdentifier; listHoverForeground?: ColorIdentifier; + listTwistieHoverBackground?: ColorIdentifier; listDropBackground?: ColorIdentifier; - listFocusOutline?: ColorIdentifier; - listInactiveFocusOutline?: ColorIdentifier; listSelectionOutline?: ColorIdentifier; listHoverOutline?: ColorIdentifier; listFilterWidgetBackground?: ColorIdentifier; @@ -236,26 +237,28 @@ export function attachListStyler(widget: IThemable, themeService: IThemeService, } export const defaultListStyles: IColorMapping = { - listFocusBackground: listFocusBackground, - listFocusForeground: listFocusForeground, - listActiveSelectionBackground: darken(listActiveSelectionBackground, 0.1), - listActiveSelectionForeground: listActiveSelectionForeground, + listFocusBackground, + listFocusForeground, + listFocusOutline, + listActiveSelectionBackground, + listActiveSelectionForeground, listFocusAndSelectionBackground: listActiveSelectionBackground, listFocusAndSelectionForeground: listActiveSelectionForeground, - listInactiveSelectionBackground: listInactiveSelectionBackground, - listInactiveSelectionForeground: listInactiveSelectionForeground, - listInactiveFocusBackground: listInactiveFocusBackground, - listHoverBackground: listHoverBackground, - listHoverForeground: listHoverForeground, - listDropBackground: listDropBackground, - listFocusOutline: activeContrastBorder, + listInactiveSelectionBackground, + listInactiveSelectionForeground, + listInactiveFocusBackground, + listInactiveFocusOutline, + listHoverBackground, + listHoverForeground, + listTwistieHoverBackground, + listDropBackground, listSelectionOutline: activeContrastBorder, listHoverOutline: activeContrastBorder, - listFilterWidgetBackground: listFilterWidgetBackground, - listFilterWidgetOutline: listFilterWidgetOutline, - listFilterWidgetNoMatchesOutline: listFilterWidgetNoMatchesOutline, + listFilterWidgetBackground, + listFilterWidgetOutline, + listFilterWidgetNoMatchesOutline, listMatchesShadow: widgetShadow, - treeIndentGuidesStroke: treeIndentGuidesStroke + treeIndentGuidesStroke }; export interface IButtonStyleOverrides extends IStyleOverrides { From 59008059d23d7f8b61610a0665fe7408a1691559 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 12 Feb 2021 11:04:42 +0100 Subject: [PATCH 049/325] add devcontainer associations to configuration-editing --- extensions/configuration-editing/package.json | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/extensions/configuration-editing/package.json b/extensions/configuration-editing/package.json index 6d99ab0d5b3..f1670e836c3 100644 --- a/extensions/configuration-editing/package.json +++ b/extensions/configuration-editing/package.json @@ -40,8 +40,12 @@ "keybindings.json", "extensions.json", "argv.json", - "profiles.json" - ] + "profiles.json", + ".devcontainer.json" + ], + "filenamePatterns": [ + "**/.devcontainer/devcontainer.json" + ] } ], "jsonValidation": [ From e7f29d65c37fb411366b8a3e94b81cac0f84e923 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 12 Feb 2021 11:12:14 +0100 Subject: [PATCH 050/325] use registerSharedProcessRemoteService to register --- .../sharedProcess/sharedProcessMain.ts | 5 +- .../userDataSync/common/userDataSyncIpc.ts | 136 ++----- .../common/userDataSyncServiceIpc.ts | 381 ++++++++++++++++++ .../electron-sandbox/userDataSyncService.ts | 256 +----------- .../userDataSyncStoreManagementService.ts | 25 +- 5 files changed, 427 insertions(+), 376 deletions(-) create mode 100644 src/vs/platform/userDataSync/common/userDataSyncServiceIpc.ts diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index d1510756240..1e4f3c62849 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -53,7 +53,7 @@ import { IProductService } from 'vs/platform/product/common/productService'; import { IUserDataSyncService, IUserDataSyncStoreService, registerConfiguration as registerUserDataSyncConfiguration, IUserDataSyncLogService, IUserDataSyncUtilService, IUserDataSyncResourceEnablementService, IUserDataSyncBackupStoreService, IUserDataSyncStoreManagementService, IUserDataAutoSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService'; import { UserDataSyncStoreService, UserDataSyncStoreManagementService } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; -import { UserDataSyncChannel, UserDataSyncUtilServiceClient, UserDataAutoSyncChannel, UserDataSyncMachinesServiceChannel, UserDataSyncAccountServiceChannel, UserDataSyncStoreManagementServiceChannel } from 'vs/platform/userDataSync/common/userDataSyncIpc'; +import { UserDataSyncUtilServiceClient, UserDataAutoSyncChannel, UserDataSyncMachinesServiceChannel, UserDataSyncAccountServiceChannel, UserDataSyncStoreManagementServiceChannel } from 'vs/platform/userDataSync/common/userDataSyncIpc'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { LoggerService } from 'vs/platform/log/node/loggerService'; import { UserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSyncLog'; @@ -81,6 +81,7 @@ import { DeprecatedExtensionsCleaner } from 'vs/code/electron-browser/sharedProc import { onUnexpectedError, setUnexpectedErrorHandler } from 'vs/base/common/errors'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { join } from 'vs/base/common/path'; +import { UserDataSyncChannel } from 'vs/platform/userDataSync/common/userDataSyncServiceIpc'; class SharedProcessMain extends Disposable { @@ -290,7 +291,7 @@ class SharedProcessMain extends Disposable { const userDataSyncStoreManagementChannel = new UserDataSyncStoreManagementServiceChannel(accessor.get(IUserDataSyncStoreManagementService)); this.server.registerChannel('userDataSyncStoreManagement', userDataSyncStoreManagementChannel); - const userDataSyncChannel = new UserDataSyncChannel(this.server, accessor.get(IUserDataSyncService), accessor.get(ILogService)); + const userDataSyncChannel = new UserDataSyncChannel(accessor.get(IUserDataSyncService), accessor.get(ILogService)); this.server.registerChannel('userDataSync', userDataSyncChannel); const userDataAutoSync = this._register(accessor.get(IInstantiationService).createInstance(UserDataAutoSyncService)); diff --git a/src/vs/platform/userDataSync/common/userDataSyncIpc.ts b/src/vs/platform/userDataSync/common/userDataSyncIpc.ts index f67dfb1c0b3..21f82c43a6d 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncIpc.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncIpc.ts @@ -3,115 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IServerChannel, IChannel, IPCServer } from 'vs/base/parts/ipc/common/ipc'; +import { IServerChannel, IChannel } from 'vs/base/parts/ipc/common/ipc'; import { Event } from 'vs/base/common/event'; -import { IUserDataSyncService, IUserDataSyncUtilService, IUserDataAutoSyncService, IManualSyncTask, IUserDataManifest, IUserDataSyncStoreManagementService, SyncStatus } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncUtilService, IUserDataAutoSyncService, IUserDataSyncStoreManagementService, UserDataSyncStoreType, IUserDataSyncStore } from 'vs/platform/userDataSync/common/userDataSync'; import { URI } from 'vs/base/common/uri'; import { IStringDictionary } from 'vs/base/common/collections'; import { FormattingOptions } from 'vs/base/common/jsonFormatter'; -import { ILogService } from 'vs/platform/log/common/log'; import { IUserDataSyncMachinesService } from 'vs/platform/userDataSync/common/userDataSyncMachines'; import { IUserDataSyncAccountService } from 'vs/platform/userDataSync/common/userDataSyncAccount'; - -export class UserDataSyncChannel implements IServerChannel { - - constructor(private server: IPCServer, private readonly service: IUserDataSyncService, private readonly logService: ILogService) { } - - listen(_: unknown, event: string): Event { - switch (event) { - case 'onDidChangeStatus': return this.service.onDidChangeStatus; - case 'onDidChangeConflicts': return this.service.onDidChangeConflicts; - case 'onDidChangeLocal': return this.service.onDidChangeLocal; - case 'onDidChangeLastSyncTime': return this.service.onDidChangeLastSyncTime; - case 'onSyncErrors': return this.service.onSyncErrors; - case 'onDidResetLocal': return this.service.onDidResetLocal; - case 'onDidResetRemote': return this.service.onDidResetRemote; - } - throw new Error(`Event not found: ${event}`); - } - - async call(context: any, command: string, args?: any): Promise { - try { - const result = await this._call(context, command, args); - return result; - } catch (e) { - this.logService.error(e); - throw e; - } - } - - private _call(context: any, command: string, args?: any): Promise { - switch (command) { - case '_getInitialData': return Promise.resolve([this.service.status, this.service.conflicts, this.service.lastSyncTime]); - - case 'createManualSyncTask': return this.createManualSyncTask(); - - case 'replace': return this.service.replace(URI.revive(args[0])); - case 'reset': return this.service.reset(); - case 'resetRemote': return this.service.resetRemote(); - case 'resetLocal': return this.service.resetLocal(); - case 'hasPreviouslySynced': return this.service.hasPreviouslySynced(); - case 'hasLocalData': return this.service.hasLocalData(); - case 'accept': return this.service.accept(args[0], URI.revive(args[1]), args[2], args[3]); - case 'resolveContent': return this.service.resolveContent(URI.revive(args[0])); - case 'getLocalSyncResourceHandles': return this.service.getLocalSyncResourceHandles(args[0]); - case 'getRemoteSyncResourceHandles': return this.service.getRemoteSyncResourceHandles(args[0]); - case 'getAssociatedResources': return this.service.getAssociatedResources(args[0], { created: args[1].created, uri: URI.revive(args[1].uri) }); - case 'getMachineId': return this.service.getMachineId(args[0], { created: args[1].created, uri: URI.revive(args[1].uri) }); - } - throw new Error('Invalid call'); - } - - private async createManualSyncTask(): Promise<{ id: string, manifest: IUserDataManifest | null, status: SyncStatus }> { - const manualSyncTask = await this.service.createManualSyncTask(); - const manualSyncTaskChannel = new ManualSyncTaskChannel(manualSyncTask, this.logService); - this.server.registerChannel(`manualSyncTask-${manualSyncTask.id}`, manualSyncTaskChannel); - return { id: manualSyncTask.id, manifest: manualSyncTask.manifest, status: manualSyncTask.status }; - } -} - -class ManualSyncTaskChannel implements IServerChannel { - - constructor( - private readonly manualSyncTask: IManualSyncTask, - private readonly logService: ILogService - ) { } - - listen(_: unknown, event: string): Event { - switch (event) { - case 'onSynchronizeResources': return this.manualSyncTask.onSynchronizeResources; - } - throw new Error(`Event not found: ${event}`); - } - - async call(context: any, command: string, args?: any): Promise { - try { - const result = await this._call(context, command, args); - return result; - } catch (e) { - this.logService.error(e); - throw e; - } - } - - private async _call(context: any, command: string, args?: any): Promise { - switch (command) { - case 'preview': return this.manualSyncTask.preview(); - case 'accept': return this.manualSyncTask.accept(URI.revive(args[0]), args[1]); - case 'merge': return this.manualSyncTask.merge(URI.revive(args[0])); - case 'discard': return this.manualSyncTask.discard(URI.revive(args[0])); - case 'discardConflicts': return this.manualSyncTask.discardConflicts(); - case 'apply': return this.manualSyncTask.apply(); - case 'pull': return this.manualSyncTask.pull(); - case 'push': return this.manualSyncTask.push(); - case 'stop': return this.manualSyncTask.stop(); - case '_getStatus': return this.manualSyncTask.status; - case 'dispose': return this.manualSyncTask.dispose(); - } - throw new Error('Invalid call'); - } - -} +import { Disposable } from 'vs/base/common/lifecycle'; export class UserDataAutoSyncChannel implements IServerChannel { @@ -235,3 +135,33 @@ export class UserDataSyncStoreManagementServiceChannel implements IServerChannel throw new Error('Invalid call'); } } + +export class UserDataSyncStoreManagementServiceChannelClient extends Disposable { + + readonly onDidChangeUserDataSyncStore: Event; + + constructor(private readonly channel: IChannel) { + super(); + this.onDidChangeUserDataSyncStore = this.channel.listen('onDidChangeUserDataSyncStore'); + } + + async switch(type: UserDataSyncStoreType): Promise { + return this.channel.call('switch', [type]); + } + + async getPreviousUserDataSyncStore(): Promise { + const userDataSyncStore = await this.channel.call('getPreviousUserDataSyncStore'); + return this.revive(userDataSyncStore); + } + + private revive(userDataSyncStore: IUserDataSyncStore): IUserDataSyncStore { + return { + url: URI.revive(userDataSyncStore.url), + defaultUrl: URI.revive(userDataSyncStore.defaultUrl), + insidersUrl: URI.revive(userDataSyncStore.insidersUrl), + stableUrl: URI.revive(userDataSyncStore.stableUrl), + canSwitch: userDataSyncStore.canSwitch, + authenticationProviders: userDataSyncStore.authenticationProviders, + }; + } +} diff --git a/src/vs/platform/userDataSync/common/userDataSyncServiceIpc.ts b/src/vs/platform/userDataSync/common/userDataSyncServiceIpc.ts new file mode 100644 index 00000000000..ee55c0be9aa --- /dev/null +++ b/src/vs/platform/userDataSync/common/userDataSyncServiceIpc.ts @@ -0,0 +1,381 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IServerChannel, IChannel } from 'vs/base/parts/ipc/common/ipc'; +import { Emitter, Event } from 'vs/base/common/event'; +import { IUserDataSyncService, IManualSyncTask, IUserDataManifest, SyncStatus, IResourcePreview, ISyncResourceHandle, ISyncResourcePreview, ISyncTask, SyncResource, UserDataSyncError } from 'vs/platform/userDataSync/common/userDataSync'; +import { URI } from 'vs/base/common/uri'; +import { ILogService } from 'vs/platform/log/common/log'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { isArray } from 'vs/base/common/types'; + +type ManualSyncTaskEvent = { manualSyncTaskId: string, data: T }; + +export class UserDataSyncChannel implements IServerChannel { + + private readonly manualSyncTasks = new Map(); + private readonly onManualSynchronizeResources = new Emitter>(); + + constructor(private readonly service: IUserDataSyncService, private readonly logService: ILogService) { } + + listen(_: unknown, event: string): Event { + switch (event) { + // sync + case 'onDidChangeStatus': return this.service.onDidChangeStatus; + case 'onDidChangeConflicts': return this.service.onDidChangeConflicts; + case 'onDidChangeLocal': return this.service.onDidChangeLocal; + case 'onDidChangeLastSyncTime': return this.service.onDidChangeLastSyncTime; + case 'onSyncErrors': return this.service.onSyncErrors; + case 'onDidResetLocal': return this.service.onDidResetLocal; + case 'onDidResetRemote': return this.service.onDidResetRemote; + + // manual sync + case 'manualSync/onSynchronizeResources': return this.onManualSynchronizeResources.event; + } + + throw new Error(`Event not found: ${event}`); + } + + async call(context: any, command: string, args?: any): Promise { + try { + const result = await this._call(context, command, args); + return result; + } catch (e) { + this.logService.error(e); + throw e; + } + } + + private async _call(context: any, command: string, args?: any): Promise { + switch (command) { + + // sync + case '_getInitialData': return Promise.resolve([this.service.status, this.service.conflicts, this.service.lastSyncTime]); + case 'replace': return this.service.replace(URI.revive(args[0])); + case 'reset': return this.service.reset(); + case 'resetRemote': return this.service.resetRemote(); + case 'resetLocal': return this.service.resetLocal(); + case 'hasPreviouslySynced': return this.service.hasPreviouslySynced(); + case 'hasLocalData': return this.service.hasLocalData(); + case 'accept': return this.service.accept(args[0], URI.revive(args[1]), args[2], args[3]); + case 'resolveContent': return this.service.resolveContent(URI.revive(args[0])); + case 'getLocalSyncResourceHandles': return this.service.getLocalSyncResourceHandles(args[0]); + case 'getRemoteSyncResourceHandles': return this.service.getRemoteSyncResourceHandles(args[0]); + case 'getAssociatedResources': return this.service.getAssociatedResources(args[0], { created: args[1].created, uri: URI.revive(args[1].uri) }); + case 'getMachineId': return this.service.getMachineId(args[0], { created: args[1].created, uri: URI.revive(args[1].uri) }); + + case 'createManualSyncTask': return this.createManualSyncTask(); + } + + // manual sync + if (command.startsWith('manualSync/')) { + const manualSyncTaskCommand = command.substring('manualSync/'.length); + const manualSyncTaskId = args[0]; + const manualSyncTask = this.getManualSyncTask(manualSyncTaskId); + args = (>args).slice(1); + + switch (manualSyncTaskCommand) { + case 'preview': return manualSyncTask.preview(); + case 'accept': return manualSyncTask.accept(URI.revive(args[0]), args[1]); + case 'merge': return manualSyncTask.merge(URI.revive(args[0])); + case 'discard': return manualSyncTask.discard(URI.revive(args[0])); + case 'discardConflicts': return manualSyncTask.discardConflicts(); + case 'apply': return manualSyncTask.apply(); + case 'pull': return manualSyncTask.pull(); + case 'push': return manualSyncTask.push(); + case 'stop': return manualSyncTask.stop(); + case '_getStatus': return manualSyncTask.status; + case 'dispose': return this.disposeManualSyncTask(manualSyncTask); + } + } + + throw new Error('Invalid call'); + } + + private getManualSyncTask(manualSyncTaskId: string): IManualSyncTask { + const value = this.manualSyncTasks.get(this.createKey(manualSyncTaskId)); + if (!value) { + throw new Error(`Manual sync taks not found: ${manualSyncTaskId}`); + } + return value.manualSyncTask; + } + + private async createManualSyncTask(): Promise<{ id: string, manifest: IUserDataManifest | null, status: SyncStatus }> { + const disposables = new DisposableStore(); + const manualSyncTask = disposables.add(await this.service.createManualSyncTask()); + disposables.add(manualSyncTask.onSynchronizeResources(synchronizeResources => this.onManualSynchronizeResources.fire({ manualSyncTaskId: manualSyncTask.id, data: synchronizeResources }))); + this.manualSyncTasks.set(this.createKey(manualSyncTask.id), { manualSyncTask, disposables }); + return { id: manualSyncTask.id, manifest: manualSyncTask.manifest, status: manualSyncTask.status }; + } + + private disposeManualSyncTask(manualSyncTask: IManualSyncTask): void { + manualSyncTask.dispose(); + const key = this.createKey(manualSyncTask.id); + this.manualSyncTasks.get(key)?.disposables.dispose(); + this.manualSyncTasks.delete(key); + } + + private createKey(manualSyncTaskId: string): string { return `manualSyncTask-${manualSyncTaskId}`; } + +} + +export class UserDataSyncChannelClient extends Disposable implements IUserDataSyncService { + + declare readonly _serviceBrand: undefined; + + private readonly channel: IChannel; + + private _status: SyncStatus = SyncStatus.Uninitialized; + get status(): SyncStatus { return this._status; } + private _onDidChangeStatus: Emitter = this._register(new Emitter()); + readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; + + get onDidChangeLocal(): Event { return this.channel.listen('onDidChangeLocal'); } + + private _conflicts: [SyncResource, IResourcePreview[]][] = []; + get conflicts(): [SyncResource, IResourcePreview[]][] { return this._conflicts; } + private _onDidChangeConflicts: Emitter<[SyncResource, IResourcePreview[]][]> = this._register(new Emitter<[SyncResource, IResourcePreview[]][]>()); + readonly onDidChangeConflicts: Event<[SyncResource, IResourcePreview[]][]> = this._onDidChangeConflicts.event; + + private _lastSyncTime: number | undefined = undefined; + get lastSyncTime(): number | undefined { return this._lastSyncTime; } + private _onDidChangeLastSyncTime: Emitter = this._register(new Emitter()); + readonly onDidChangeLastSyncTime: Event = this._onDidChangeLastSyncTime.event; + + private _onSyncErrors: Emitter<[SyncResource, UserDataSyncError][]> = this._register(new Emitter<[SyncResource, UserDataSyncError][]>()); + readonly onSyncErrors: Event<[SyncResource, UserDataSyncError][]> = this._onSyncErrors.event; + + get onDidResetLocal(): Event { return this.channel.listen('onDidResetLocal'); } + get onDidResetRemote(): Event { return this.channel.listen('onDidResetRemote'); } + + constructor(userDataSyncChannel: IChannel) { + super(); + this.channel = { + call(command: string, arg?: any, cancellationToken?: CancellationToken): Promise { + return userDataSyncChannel.call(command, arg, cancellationToken) + .then(null, error => { throw UserDataSyncError.toUserDataSyncError(error); }); + }, + listen(event: string, arg?: any): Event { + return userDataSyncChannel.listen(event, arg); + } + }; + this.channel.call<[SyncStatus, [SyncResource, IResourcePreview[]][], number | undefined]>('_getInitialData').then(([status, conflicts, lastSyncTime]) => { + this.updateStatus(status); + this.updateConflicts(conflicts); + if (lastSyncTime) { + this.updateLastSyncTime(lastSyncTime); + } + this._register(this.channel.listen('onDidChangeStatus')(status => this.updateStatus(status))); + this._register(this.channel.listen('onDidChangeLastSyncTime')(lastSyncTime => this.updateLastSyncTime(lastSyncTime))); + }); + this._register(this.channel.listen<[SyncResource, IResourcePreview[]][]>('onDidChangeConflicts')(conflicts => this.updateConflicts(conflicts))); + this._register(this.channel.listen<[SyncResource, Error][]>('onSyncErrors')(errors => this._onSyncErrors.fire(errors.map(([source, error]) => ([source, UserDataSyncError.toUserDataSyncError(error)]))))); + } + + createSyncTask(): Promise { + throw new Error('not supported'); + } + + async createManualSyncTask(): Promise { + const { id, manifest, status } = await this.channel.call<{ id: string, manifest: IUserDataManifest | null, status: SyncStatus }>('createManualSyncTask'); + const that = this; + const manualSyncTaskChannelClient = new ManualSyncTaskChannelClient(id, manifest, status, { + async call(command: string, arg?: any, cancellationToken?: CancellationToken): Promise { + return that.channel.call(`manualSync/${command}`, [id, ...(isArray(arg) ? arg : [arg])], cancellationToken); + }, + listen(event: string, arg?: any): Event { + return Event.map( + Event.filter(that.channel.listen<{ manualSyncTaskId: string, data: T }>(`manualSync/${event}`, arg), e => !manualSyncTaskChannelClient.isDiposed() && e.manualSyncTaskId === id), + e => e.data); + } + }); + return manualSyncTaskChannelClient; + } + + replace(uri: URI): Promise { + return this.channel.call('replace', [uri]); + } + + reset(): Promise { + return this.channel.call('reset'); + } + + resetRemote(): Promise { + return this.channel.call('resetRemote'); + } + + resetLocal(): Promise { + return this.channel.call('resetLocal'); + } + + hasPreviouslySynced(): Promise { + return this.channel.call('hasPreviouslySynced'); + } + + hasLocalData(): Promise { + return this.channel.call('hasLocalData'); + } + + accept(syncResource: SyncResource, resource: URI, content: string | null, apply: boolean): Promise { + return this.channel.call('accept', [syncResource, resource, content, apply]); + } + + resolveContent(resource: URI): Promise { + return this.channel.call('resolveContent', [resource]); + } + + async getLocalSyncResourceHandles(resource: SyncResource): Promise { + const handles = await this.channel.call('getLocalSyncResourceHandles', [resource]); + return handles.map(({ created, uri }) => ({ created, uri: URI.revive(uri) })); + } + + async getRemoteSyncResourceHandles(resource: SyncResource): Promise { + const handles = await this.channel.call('getRemoteSyncResourceHandles', [resource]); + return handles.map(({ created, uri }) => ({ created, uri: URI.revive(uri) })); + } + + async getAssociatedResources(resource: SyncResource, syncResourceHandle: ISyncResourceHandle): Promise<{ resource: URI, comparableResource: URI }[]> { + const result = await this.channel.call<{ resource: URI, comparableResource: URI }[]>('getAssociatedResources', [resource, syncResourceHandle]); + return result.map(({ resource, comparableResource }) => ({ resource: URI.revive(resource), comparableResource: URI.revive(comparableResource) })); + } + + async getMachineId(resource: SyncResource, syncResourceHandle: ISyncResourceHandle): Promise { + return this.channel.call('getMachineId', [resource, syncResourceHandle]); + } + + private async updateStatus(status: SyncStatus): Promise { + this._status = status; + this._onDidChangeStatus.fire(status); + } + + private async updateConflicts(conflicts: [SyncResource, IResourcePreview[]][]): Promise { + // Revive URIs + this._conflicts = conflicts.map(([syncResource, conflicts]) => + ([ + syncResource, + conflicts.map(r => + ({ + ...r, + localResource: URI.revive(r.localResource), + remoteResource: URI.revive(r.remoteResource), + previewResource: URI.revive(r.previewResource), + })) + ])); + this._onDidChangeConflicts.fire(this._conflicts); + } + + private updateLastSyncTime(lastSyncTime: number): void { + if (this._lastSyncTime !== lastSyncTime) { + this._lastSyncTime = lastSyncTime; + this._onDidChangeLastSyncTime.fire(lastSyncTime); + } + } +} + +class ManualSyncTaskChannelClient extends Disposable implements IManualSyncTask { + + private readonly channel: IChannel; + + get onSynchronizeResources(): Event<[SyncResource, URI[]][]> { return this.channel.listen<[SyncResource, URI[]][]>('onSynchronizeResources'); } + + private _status: SyncStatus; + get status(): SyncStatus { return this._status; } + + constructor( + readonly id: string, + readonly manifest: IUserDataManifest | null, + status: SyncStatus, + manualSyncTaskChannel: IChannel + ) { + super(); + this._status = status; + const that = this; + this.channel = { + async call(command: string, arg?: any, cancellationToken?: CancellationToken): Promise { + try { + const result = await manualSyncTaskChannel.call(command, arg, cancellationToken); + if (!that.isDiposed()) { + that._status = await manualSyncTaskChannel.call('_getStatus'); + } + return result; + } catch (error) { + throw UserDataSyncError.toUserDataSyncError(error); + } + }, + listen(event: string, arg?: any): Event { + return manualSyncTaskChannel.listen(event, arg); + } + }; + } + + async preview(): Promise<[SyncResource, ISyncResourcePreview][]> { + const previews = await this.channel.call<[SyncResource, ISyncResourcePreview][]>('preview'); + return this.deserializePreviews(previews); + } + + async accept(resource: URI, content?: string | null): Promise<[SyncResource, ISyncResourcePreview][]> { + const previews = await this.channel.call<[SyncResource, ISyncResourcePreview][]>('accept', [resource, content]); + return this.deserializePreviews(previews); + } + + async merge(resource?: URI): Promise<[SyncResource, ISyncResourcePreview][]> { + const previews = await this.channel.call<[SyncResource, ISyncResourcePreview][]>('merge', [resource]); + return this.deserializePreviews(previews); + } + + async discard(resource: URI): Promise<[SyncResource, ISyncResourcePreview][]> { + const previews = await this.channel.call<[SyncResource, ISyncResourcePreview][]>('discard', [resource]); + return this.deserializePreviews(previews); + } + + async discardConflicts(): Promise<[SyncResource, ISyncResourcePreview][]> { + const previews = await this.channel.call<[SyncResource, ISyncResourcePreview][]>('discardConflicts'); + return this.deserializePreviews(previews); + } + + async apply(): Promise<[SyncResource, ISyncResourcePreview][]> { + const previews = await this.channel.call<[SyncResource, ISyncResourcePreview][]>('apply'); + return this.deserializePreviews(previews); + } + + pull(): Promise { + return this.channel.call('pull'); + } + + push(): Promise { + return this.channel.call('push'); + } + + stop(): Promise { + return this.channel.call('stop'); + } + + private _disposed = false; + isDiposed() { return this._disposed; } + + dispose(): void { + this._disposed = true; + this.channel.call('dispose'); + } + + private deserializePreviews(previews: [SyncResource, ISyncResourcePreview][]): [SyncResource, ISyncResourcePreview][] { + return previews.map(([syncResource, preview]) => + ([ + syncResource, + { + isLastSyncFromCurrentMachine: preview.isLastSyncFromCurrentMachine, + resourcePreviews: preview.resourcePreviews.map(r => ({ + ...r, + localResource: URI.revive(r.localResource), + remoteResource: URI.revive(r.remoteResource), + previewResource: URI.revive(r.previewResource), + acceptedResource: URI.revive(r.acceptedResource), + })) + } + ])); + } +} + diff --git a/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncService.ts b/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncService.ts index 8e4493669f3..59ca1f122e8 100644 --- a/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncService.ts +++ b/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncService.ts @@ -3,256 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { SyncStatus, SyncResource, IUserDataSyncService, UserDataSyncError, ISyncResourceHandle, ISyncTask, IManualSyncTask, IUserDataManifest, ISyncResourcePreview, IResourcePreview } from 'vs/platform/userDataSync/common/userDataSync'; -import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/services'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { Emitter, Event } from 'vs/base/common/event'; -import { IChannel } from 'vs/base/parts/ipc/common/ipc'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { CancellationToken } from 'vs/base/common/cancellation'; -import { URI } from 'vs/base/common/uri'; +import { IUserDataSyncService } from 'vs/platform/userDataSync/common/userDataSync'; +import { registerSharedProcessRemoteService } from 'vs/platform/ipc/electron-sandbox/services'; +import { UserDataSyncChannelClient } from 'vs/platform/userDataSync/common/userDataSyncServiceIpc'; -export class UserDataSyncService extends Disposable implements IUserDataSyncService { - - declare readonly _serviceBrand: undefined; - - private readonly channel: IChannel; - - private _status: SyncStatus = SyncStatus.Uninitialized; - get status(): SyncStatus { return this._status; } - private _onDidChangeStatus: Emitter = this._register(new Emitter()); - readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; - - get onDidChangeLocal(): Event { return this.channel.listen('onDidChangeLocal'); } - - private _conflicts: [SyncResource, IResourcePreview[]][] = []; - get conflicts(): [SyncResource, IResourcePreview[]][] { return this._conflicts; } - private _onDidChangeConflicts: Emitter<[SyncResource, IResourcePreview[]][]> = this._register(new Emitter<[SyncResource, IResourcePreview[]][]>()); - readonly onDidChangeConflicts: Event<[SyncResource, IResourcePreview[]][]> = this._onDidChangeConflicts.event; - - private _lastSyncTime: number | undefined = undefined; - get lastSyncTime(): number | undefined { return this._lastSyncTime; } - private _onDidChangeLastSyncTime: Emitter = this._register(new Emitter()); - readonly onDidChangeLastSyncTime: Event = this._onDidChangeLastSyncTime.event; - - private _onSyncErrors: Emitter<[SyncResource, UserDataSyncError][]> = this._register(new Emitter<[SyncResource, UserDataSyncError][]>()); - readonly onSyncErrors: Event<[SyncResource, UserDataSyncError][]> = this._onSyncErrors.event; - - get onDidResetLocal(): Event { return this.channel.listen('onDidResetLocal'); } - get onDidResetRemote(): Event { return this.channel.listen('onDidResetRemote'); } - - constructor( - @ISharedProcessService private readonly sharedProcessService: ISharedProcessService - ) { - super(); - const userDataSyncChannel = sharedProcessService.getChannel('userDataSync'); - this.channel = { - call(command: string, arg?: any, cancellationToken?: CancellationToken): Promise { - return userDataSyncChannel.call(command, arg, cancellationToken) - .then(null, error => { throw UserDataSyncError.toUserDataSyncError(error); }); - }, - listen(event: string, arg?: any): Event { - return userDataSyncChannel.listen(event, arg); - } - }; - this.channel.call<[SyncStatus, [SyncResource, IResourcePreview[]][], number | undefined]>('_getInitialData').then(([status, conflicts, lastSyncTime]) => { - this.updateStatus(status); - this.updateConflicts(conflicts); - if (lastSyncTime) { - this.updateLastSyncTime(lastSyncTime); - } - this._register(this.channel.listen('onDidChangeStatus')(status => this.updateStatus(status))); - this._register(this.channel.listen('onDidChangeLastSyncTime')(lastSyncTime => this.updateLastSyncTime(lastSyncTime))); - }); - this._register(this.channel.listen<[SyncResource, IResourcePreview[]][]>('onDidChangeConflicts')(conflicts => this.updateConflicts(conflicts))); - this._register(this.channel.listen<[SyncResource, Error][]>('onSyncErrors')(errors => this._onSyncErrors.fire(errors.map(([source, error]) => ([source, UserDataSyncError.toUserDataSyncError(error)]))))); - } - - createSyncTask(): Promise { - throw new Error('not supported'); - } - - async createManualSyncTask(): Promise { - const { id, manifest, status } = await this.channel.call<{ id: string, manifest: IUserDataManifest | null, status: SyncStatus }>('createManualSyncTask'); - return new ManualSyncTask(id, manifest, status, this.sharedProcessService); - } - - replace(uri: URI): Promise { - return this.channel.call('replace', [uri]); - } - - reset(): Promise { - return this.channel.call('reset'); - } - - resetRemote(): Promise { - return this.channel.call('resetRemote'); - } - - resetLocal(): Promise { - return this.channel.call('resetLocal'); - } - - hasPreviouslySynced(): Promise { - return this.channel.call('hasPreviouslySynced'); - } - - hasLocalData(): Promise { - return this.channel.call('hasLocalData'); - } - - accept(syncResource: SyncResource, resource: URI, content: string | null, apply: boolean): Promise { - return this.channel.call('accept', [syncResource, resource, content, apply]); - } - - resolveContent(resource: URI): Promise { - return this.channel.call('resolveContent', [resource]); - } - - async getLocalSyncResourceHandles(resource: SyncResource): Promise { - const handles = await this.channel.call('getLocalSyncResourceHandles', [resource]); - return handles.map(({ created, uri }) => ({ created, uri: URI.revive(uri) })); - } - - async getRemoteSyncResourceHandles(resource: SyncResource): Promise { - const handles = await this.channel.call('getRemoteSyncResourceHandles', [resource]); - return handles.map(({ created, uri }) => ({ created, uri: URI.revive(uri) })); - } - - async getAssociatedResources(resource: SyncResource, syncResourceHandle: ISyncResourceHandle): Promise<{ resource: URI, comparableResource: URI }[]> { - const result = await this.channel.call<{ resource: URI, comparableResource: URI }[]>('getAssociatedResources', [resource, syncResourceHandle]); - return result.map(({ resource, comparableResource }) => ({ resource: URI.revive(resource), comparableResource: URI.revive(comparableResource) })); - } - - async getMachineId(resource: SyncResource, syncResourceHandle: ISyncResourceHandle): Promise { - return this.channel.call('getMachineId', [resource, syncResourceHandle]); - } - - private async updateStatus(status: SyncStatus): Promise { - this._status = status; - this._onDidChangeStatus.fire(status); - } - - private async updateConflicts(conflicts: [SyncResource, IResourcePreview[]][]): Promise { - // Revive URIs - this._conflicts = conflicts.map(([syncResource, conflicts]) => - ([ - syncResource, - conflicts.map(r => - ({ - ...r, - localResource: URI.revive(r.localResource), - remoteResource: URI.revive(r.remoteResource), - previewResource: URI.revive(r.previewResource), - })) - ])); - this._onDidChangeConflicts.fire(this._conflicts); - } - - private updateLastSyncTime(lastSyncTime: number): void { - if (this._lastSyncTime !== lastSyncTime) { - this._lastSyncTime = lastSyncTime; - this._onDidChangeLastSyncTime.fire(lastSyncTime); - } - } -} - -class ManualSyncTask implements IManualSyncTask { - - private readonly channel: IChannel; - - get onSynchronizeResources(): Event<[SyncResource, URI[]][]> { return this.channel.listen<[SyncResource, URI[]][]>('onSynchronizeResources'); } - - private _status: SyncStatus; - get status(): SyncStatus { return this._status; } - - constructor( - readonly id: string, - readonly manifest: IUserDataManifest | null, - status: SyncStatus, - sharedProcessService: ISharedProcessService, - ) { - const manualSyncTaskChannel = sharedProcessService.getChannel(`manualSyncTask-${id}`); - this._status = status; - const that = this; - this.channel = { - async call(command: string, arg?: any, cancellationToken?: CancellationToken): Promise { - try { - const result = await manualSyncTaskChannel.call(command, arg, cancellationToken); - that._status = await manualSyncTaskChannel.call('_getStatus'); - return result; - } catch (error) { - throw UserDataSyncError.toUserDataSyncError(error); - } - }, - listen(event: string, arg?: any): Event { - return manualSyncTaskChannel.listen(event, arg); - } - }; - } - - async preview(): Promise<[SyncResource, ISyncResourcePreview][]> { - const previews = await this.channel.call<[SyncResource, ISyncResourcePreview][]>('preview'); - return this.deserializePreviews(previews); - } - - async accept(resource: URI, content?: string | null): Promise<[SyncResource, ISyncResourcePreview][]> { - const previews = await this.channel.call<[SyncResource, ISyncResourcePreview][]>('accept', [resource, content]); - return this.deserializePreviews(previews); - } - - async merge(resource?: URI): Promise<[SyncResource, ISyncResourcePreview][]> { - const previews = await this.channel.call<[SyncResource, ISyncResourcePreview][]>('merge', [resource]); - return this.deserializePreviews(previews); - } - - async discard(resource: URI): Promise<[SyncResource, ISyncResourcePreview][]> { - const previews = await this.channel.call<[SyncResource, ISyncResourcePreview][]>('discard', [resource]); - return this.deserializePreviews(previews); - } - - async discardConflicts(): Promise<[SyncResource, ISyncResourcePreview][]> { - const previews = await this.channel.call<[SyncResource, ISyncResourcePreview][]>('discardConflicts'); - return this.deserializePreviews(previews); - } - - async apply(): Promise<[SyncResource, ISyncResourcePreview][]> { - const previews = await this.channel.call<[SyncResource, ISyncResourcePreview][]>('apply'); - return this.deserializePreviews(previews); - } - - pull(): Promise { - return this.channel.call('pull'); - } - - push(): Promise { - return this.channel.call('push'); - } - - stop(): Promise { - return this.channel.call('stop'); - } - - dispose(): void { - this.channel.call('dispose'); - } - - private deserializePreviews(previews: [SyncResource, ISyncResourcePreview][]): [SyncResource, ISyncResourcePreview][] { - return previews.map(([syncResource, preview]) => - ([ - syncResource, - { - isLastSyncFromCurrentMachine: preview.isLastSyncFromCurrentMachine, - resourcePreviews: preview.resourcePreviews.map(r => ({ - ...r, - localResource: URI.revive(r.localResource), - remoteResource: URI.revive(r.remoteResource), - previewResource: URI.revive(r.previewResource), - acceptedResource: URI.revive(r.acceptedResource), - })) - } - ])); - } -} - -registerSingleton(IUserDataSyncService, UserDataSyncService); +registerSharedProcessRemoteService(IUserDataSyncService, 'userDataSync', { channelClientCtor: UserDataSyncChannelClient }); diff --git a/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncStoreManagementService.ts b/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncStoreManagementService.ts index c42315a7454..32d1362bf3a 100644 --- a/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncStoreManagementService.ts +++ b/src/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncStoreManagementService.ts @@ -5,17 +5,16 @@ import { IUserDataSyncStoreManagementService, UserDataSyncStoreType, IUserDataSyncStore } from 'vs/platform/userDataSync/common/userDataSync'; import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/services'; -import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { AbstractUserDataSyncStoreManagementService } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; import { IProductService } from 'vs/platform/product/common/productService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { URI } from 'vs/base/common/uri'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { UserDataSyncStoreManagementServiceChannelClient } from 'vs/platform/userDataSync/common/userDataSyncIpc'; class UserDataSyncStoreManagementService extends AbstractUserDataSyncStoreManagementService implements IUserDataSyncStoreManagementService { - private readonly channel: IChannel; + private readonly channelClient: UserDataSyncStoreManagementServiceChannelClient; constructor( @IProductService productService: IProductService, @@ -24,28 +23,16 @@ class UserDataSyncStoreManagementService extends AbstractUserDataSyncStoreManage @ISharedProcessService sharedProcessService: ISharedProcessService, ) { super(productService, configurationService, storageService); - this.channel = sharedProcessService.getChannel('userDataSyncStoreManagement'); - this._register(this.channel.listen('onDidChangeUserDataSyncStore')(() => this.updateUserDataSyncStore())); + this.channelClient = this._register(new UserDataSyncStoreManagementServiceChannelClient(sharedProcessService.getChannel('userDataSyncStoreManagement'))); + this._register(this.channelClient.onDidChangeUserDataSyncStore(() => this.updateUserDataSyncStore())); } async switch(type: UserDataSyncStoreType): Promise { - return this.channel.call('switch', [type]); + return this.channelClient.switch(type); } async getPreviousUserDataSyncStore(): Promise { - const userDataSyncStore = await this.channel.call('getPreviousUserDataSyncStore'); - return this.revive(userDataSyncStore); - } - - private revive(userDataSyncStore: IUserDataSyncStore): IUserDataSyncStore { - return { - url: URI.revive(userDataSyncStore.url), - defaultUrl: URI.revive(userDataSyncStore.defaultUrl), - insidersUrl: URI.revive(userDataSyncStore.insidersUrl), - stableUrl: URI.revive(userDataSyncStore.stableUrl), - canSwitch: userDataSyncStore.canSwitch, - authenticationProviders: userDataSyncStore.authenticationProviders, - }; + return this.channelClient.getPreviousUserDataSyncStore(); } } From 2384f4de731f0e4bd519d8c7f531ac1f8cf270cc Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 12 Feb 2021 11:13:10 +0100 Subject: [PATCH 051/325] Accessibility: Shift+Tab gets trapped in debug and problems panes. fixes #116525 --- src/vs/base/browser/ui/actionbar/actionbar.ts | 8 ++------ .../workbench/contrib/debug/browser/replFilter.ts | 14 +++++++++++++- .../contrib/markers/browser/markersViewActions.ts | 10 ++++++++++ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index b4450cc869f..e02edc21588 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -148,12 +148,8 @@ export class ActionBar extends Disposable implements IActionRunner { eventHandled = this.focusNext(); } else if (event.equals(KeyCode.Escape) && this.cancelHasListener) { this._onDidCancel.fire(); - } else if ((event.equals(KeyCode.Tab) || event.equals(KeyMod.Shift | KeyCode.Tab)) && focusedItem instanceof BaseActionViewItem && focusedItem.trapsArrowNavigation) { - if (event.equals(KeyCode.Tab)) { - this.focusNext(); - } else { - this.focusPrevious(); - } + } else if (event.equals(KeyCode.Tab) && focusedItem instanceof BaseActionViewItem && focusedItem.trapsArrowNavigation) { + this.focusNext(); } else if (this.isTriggerKeyEvent(event)) { // Staying out of the else branch even if not triggered if (this._triggerKeys.keyDown) { diff --git a/src/vs/workbench/contrib/debug/browser/replFilter.ts b/src/vs/workbench/contrib/debug/browser/replFilter.ts index 668a3f0294b..15f2c7bed61 100644 --- a/src/vs/workbench/contrib/debug/browser/replFilter.ts +++ b/src/vs/workbench/contrib/debug/browser/replFilter.ts @@ -158,7 +158,19 @@ export class ReplFilterActionViewItem extends BaseActionViewItem { } focus(): void { - this.filterInputBox.focus(); + if (this.filterInputBox) { + this.filterInputBox.focus(); + } + } + + blur(): void { + if (this.filterInputBox) { + this.filterInputBox.blur(); + } + } + + setFocusable(): void { + // noop input elements are focusable by default } getHistory(): string[] { diff --git a/src/vs/workbench/contrib/markers/browser/markersViewActions.ts b/src/vs/workbench/contrib/markers/browser/markersViewActions.ts index 2a6fc629fe3..2653e238d6f 100644 --- a/src/vs/workbench/contrib/markers/browser/markersViewActions.ts +++ b/src/vs/workbench/contrib/markers/browser/markersViewActions.ts @@ -283,6 +283,16 @@ export class MarkersFilterActionViewItem extends BaseActionViewItem { } } + blur(): void { + if (this.filterInputBox) { + this.filterInputBox.blur(); + } + } + + setFocusable(): void { + // noop input elements are focusable by default + } + get trapsArrowNavigation(): boolean { return true; } From fc31a6a558479c92bad51918f282c8db408b9db9 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 12 Feb 2021 11:15:50 +0100 Subject: [PATCH 052/325] skip failing test, https://github.com/microsoft/vscode/issues/116535 --- test/smoke/src/areas/notebook/notebook.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/smoke/src/areas/notebook/notebook.test.ts b/test/smoke/src/areas/notebook/notebook.test.ts index 1d70ee93a89..27f8269954b 100644 --- a/test/smoke/src/areas/notebook/notebook.test.ts +++ b/test/smoke/src/areas/notebook/notebook.test.ts @@ -34,7 +34,7 @@ export function setup() { await app.workbench.notebook.stopEditingCell(); }); - it('inserts/edits markdown cell', async function () { + it.skip('inserts/edits markdown cell', async function () { const app = this.app as Application; await app.workbench.notebook.openNotebook(); await app.workbench.notebook.focusNextCell(); From 570890ca7e6d1ccb61630a1bdece0675be44f3df Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 12 Feb 2021 13:58:11 +0100 Subject: [PATCH 053/325] :lipstick: --- src/vs/editor/contrib/suggest/wordContextKey.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/contrib/suggest/wordContextKey.ts b/src/vs/editor/contrib/suggest/wordContextKey.ts index a9558304bac..81e80cf74f2 100644 --- a/src/vs/editor/contrib/suggest/wordContextKey.ts +++ b/src/vs/editor/contrib/suggest/wordContextKey.ts @@ -4,15 +4,16 @@ *--------------------------------------------------------------------------------------------*/ import { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; -export class WordContextKey extends Disposable { +export class WordContextKey { static readonly AtEnd = new RawContextKey('atEndOfWord', false); private readonly _ckAtEnd: IContextKey; + private readonly _configListener: IDisposable; private _enabled: boolean = false; private _selectionListener?: IDisposable; @@ -21,14 +22,14 @@ export class WordContextKey extends Disposable { private readonly _editor: ICodeEditor, @IContextKeyService contextKeyService: IContextKeyService, ) { - super(); + this._ckAtEnd = WordContextKey.AtEnd.bindTo(contextKeyService); - this._register(this._editor.onDidChangeConfiguration(e => e.hasChanged(EditorOption.tabCompletion) && this._update())); + this._configListener = this._editor.onDidChangeConfiguration(e => e.hasChanged(EditorOption.tabCompletion) && this._update()); this._update(); } dispose(): void { - super.dispose(); + this._configListener.dispose(); this._selectionListener?.dispose(); this._ckAtEnd.reset(); } From f507f5ca343788e8264a5bcbd370be900cf2b2ee Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Fri, 12 Feb 2021 14:04:30 +0100 Subject: [PATCH 054/325] Setup tunnels for syncing --- .../contrib/remote/browser/tunnelView.ts | 2 +- .../remote/common/remoteExplorerService.ts | 62 ++++++++++++++----- 2 files changed, 47 insertions(+), 17 deletions(-) diff --git a/src/vs/workbench/contrib/remote/browser/tunnelView.ts b/src/vs/workbench/contrib/remote/browser/tunnelView.ts index 0df43ba61ce..daa3fba23f9 100644 --- a/src/vs/workbench/contrib/remote/browser/tunnelView.ts +++ b/src/vs/workbench/contrib/remote/browser/tunnelView.ts @@ -829,7 +829,7 @@ namespace LabelTunnelAction { remoteExplorerService.setEditable(context, { onFinish: async (value, success) => { if (success) { - remoteExplorerService.tunnelModel.name(context.remoteHost, context.remotePort, value); + await remoteExplorerService.tunnelModel.name(context.remoteHost, context.remotePort, value); } remoteExplorerService.setEditable(context, null); resolve(success ? { port: context.remotePort, label: value } : undefined); diff --git a/src/vs/workbench/services/remote/common/remoteExplorerService.ts b/src/vs/workbench/services/remote/common/remoteExplorerService.ts index 89c8acfcae0..e066dffffef 100644 --- a/src/vs/workbench/services/remote/common/remoteExplorerService.ts +++ b/src/vs/workbench/services/remote/common/remoteExplorerService.ts @@ -16,6 +16,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { IAddressProvider } from 'vs/platform/remote/common/remoteAgentConnection'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { isNumber, isObject, isString } from 'vs/base/common/types'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; export const IRemoteExplorerService = createDecorator('remoteExplorerService'); export const REMOTE_EXPLORER_TYPE_KEY: string = 'remote.explorerType'; @@ -244,7 +245,7 @@ export class TunnelModel extends Disposable { // onCandidateChanged returns the removed candidates public onCandidatesChanged: Event> = this._onCandidatesChanged.event; private _candidateFilter: ((candidates: CandidatePort[]) => Promise) | undefined; - private tunnelRestoreValue: string | undefined; + private tunnelRestoreValue: Promise; private _onEnvironmentTunnelsSet: Emitter = new Emitter(); public onEnvironmentTunnelsSet: Event = this._onEnvironmentTunnelsSet.event; private _environmentTunnelsSet: boolean = false; @@ -256,10 +257,11 @@ export class TunnelModel extends Disposable { @IConfigurationService private readonly configurationService: IConfigurationService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @IRemoteAuthorityResolverService private readonly remoteAuthorityResolverService: IRemoteAuthorityResolverService, + @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService ) { super(); this.portsAttributes = new PortsAttributes(configurationService); - this.tunnelRestoreValue = this.storageService.get(TUNNELS_TO_RESTORE, StorageScope.WORKSPACE); + this.tunnelRestoreValue = this.getTunnelRestoreValue(); this.forwarded = new Map(); this.remoteTunnels = new Map(); this.tunnelService.tunnels.then(tunnels => { @@ -283,7 +285,7 @@ export class TunnelModel extends Disposable { }); this.detected = new Map(); - this._register(this.tunnelService.onTunnelOpened(tunnel => { + this._register(this.tunnelService.onTunnelOpened(async (tunnel) => { const key = makeAddress(tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort); if ((!this.forwarded.has(key)) && tunnel.localAddress) { const matchingCandidate = mapHasAddressLocalhostOrAllInterfaces(this._candidates ?? new Map(), tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort); @@ -299,15 +301,15 @@ export class TunnelModel extends Disposable { restore: true }); } - this.storeForwarded(); + await this.storeForwarded(); this.remoteTunnels.set(key, tunnel); this._onForwardPort.fire(this.forwarded.get(key)!); })); - this._register(this.tunnelService.onTunnelClosed(address => { + this._register(this.tunnelService.onTunnelClosed(async (address) => { const key = makeAddress(address.host, address.port); if (this.forwarded.has(key)) { this.forwarded.delete(key); - this.storeForwarded(); + await this.storeForwarded(); this._onClosePort.fire(address); } })); @@ -319,22 +321,49 @@ export class TunnelModel extends Disposable { return isPublic ? TunnelPrivacy.Public : this.tunnelService.canMakePublic ? TunnelPrivacy.Private : TunnelPrivacy.ConstantPrivate; } + private async getStorageKey(): Promise { + const workspace = this.workspaceContextService.getWorkspace(); + return `${TUNNELS_TO_RESTORE}.${this.environmentService.remoteAuthority}.${workspace.id}`; + } + + private async getTunnelRestoreValue(): Promise { + const deprecatedValue = this.storageService.get(TUNNELS_TO_RESTORE, StorageScope.WORKSPACE); + if (deprecatedValue) { + this.storageService.remove(TUNNELS_TO_RESTORE, StorageScope.WORKSPACE); + await this.storeForwarded(); + return deprecatedValue; + } + + return this.storageService.get(await this.getStorageKey(), StorageScope.GLOBAL); + } + async restoreForwarded() { if (this.configurationService.getValue('remote.restoreForwardedPorts')) { - if (this.tunnelRestoreValue) { - const tunnels = JSON.parse(this.tunnelRestoreValue) ?? []; + const tunnelRestoreValue = await this.tunnelRestoreValue; + if (tunnelRestoreValue) { + const tunnels = JSON.parse(tunnelRestoreValue) ?? []; for (let tunnel of tunnels) { if (!mapHasAddressLocalhostOrAllInterfaces(this.detected, tunnel.remoteHost, tunnel.remotePort)) { await this.forward({ host: tunnel.remoteHost, port: tunnel.remotePort }, tunnel.localPort, tunnel.name, undefined, undefined, tunnel.privacy === TunnelPrivacy.Public); } } + } else { + // It's possible that at restore time the value hasn't synced. + const key = await this.getStorageKey(); + const listener = this.storageService.onDidChangeValue(async (e) => { + if (e.key === key) { + listener.dispose(); + this.tunnelRestoreValue = Promise.resolve(this.storageService.get(await this.getStorageKey(), StorageScope.GLOBAL)); + await this.restoreForwarded(); + } + }); } } } - private storeForwarded() { + private async storeForwarded() { if (this.configurationService.getValue('remote.restoreForwardedPorts')) { - this.storageService.store(TUNNELS_TO_RESTORE, JSON.stringify(Array.from(this.forwarded.values()).filter(value => value.restore)), StorageScope.WORKSPACE, StorageTarget.USER); + this.storageService.store(await this.getStorageKey(), JSON.stringify(Array.from(this.forwarded.values()).filter(value => value.restore)), StorageScope.GLOBAL, StorageTarget.USER); } } @@ -367,7 +396,7 @@ export class TunnelModel extends Disposable { const key = makeAddress(remote.host, remote.port); this.forwarded.set(key, newForward); this.remoteTunnels.set(key, tunnel); - this.storeForwarded(); + await this.storeForwarded(); this._onForwardPort.fire(newForward); return tunnel; } @@ -380,12 +409,12 @@ export class TunnelModel extends Disposable { } } - name(host: string, port: number, name: string) { + async name(host: string, port: number, name: string) { const existingForwarded = mapHasAddressLocalhostOrAllInterfaces(this.forwarded, host, port); const key = makeAddress(host, port); if (existingForwarded) { existingForwarded.name = name; - this.storeForwarded(); + await this.storeForwarded(); this._onPortName.fire({ host, port }); return; } else if (this.detected.has(key)) { @@ -492,12 +521,12 @@ export class TunnelModel extends Disposable { return this._candidates ? this.candidates : undefined; } - private updateAttributes() { + private async updateAttributes() { // If the label changes in the attributes, we should update it. for (let forwarded of this.forwarded.values()) { const attributes = this.portsAttributes.getAttributes(forwarded.remotePort); if (attributes && attributes.label && attributes.label !== forwarded.name) { - this.name(forwarded.remoteHost, forwarded.remotePort, attributes.label); + await this.name(forwarded.remoteHost, forwarded.remotePort, attributes.label); } } } @@ -550,8 +579,9 @@ class RemoteExplorerService implements IRemoteExplorerService { @IConfigurationService configurationService: IConfigurationService, @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @IRemoteAuthorityResolverService remoteAuthorityResolverService: IRemoteAuthorityResolverService, + @IWorkspaceContextService workspaceContextService: IWorkspaceContextService ) { - this._tunnelModel = new TunnelModel(tunnelService, storageService, configurationService, environmentService, remoteAuthorityResolverService); + this._tunnelModel = new TunnelModel(tunnelService, storageService, configurationService, environmentService, remoteAuthorityResolverService, workspaceContextService); } set targetType(name: string[]) { From 5a7711ac92831fad702b0e06a85ec328d7f769f8 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 12 Feb 2021 14:29:06 +0100 Subject: [PATCH 055/325] :lipstick: --- .../api/browser/mainThreadNotebook.ts | 55 +++++++++---------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts index 617f46a2a2c..8271fcb3dd4 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -112,23 +112,22 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo private readonly _notebookProviders = new Map(); private readonly _notebookKernelProviders = new Map, provider: IDisposable }>(); private readonly _proxy: ExtHostNotebookShape; - private _toDisposeOnEditorRemove = new Map(); + private readonly _toDisposeOnEditorRemove = new Map(); private _currentState?: DocumentAndEditorState; - private _editorEventListenersMapping: Map = new Map(); - private _documentEventListenersMapping: ResourceMap = new ResourceMap(); + private readonly _editorEventListenersMapping: Map = new Map(); + private readonly _documentEventListenersMapping: ResourceMap = new ResourceMap(); private readonly _cellStatusBarEntries: Map = new Map(); private readonly _modelReferenceCollection: BoundModelReferenceCollection; constructor( extHostContext: IExtHostContext, @INotebookService private _notebookService: INotebookService, - @IConfigurationService private readonly configurationService: IConfigurationService, - @IEditorService private readonly editorService: IEditorService, - @IEditorGroupsService private readonly editorGroupsService: IEditorGroupsService, - @IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService, - @IAccessibilityService private readonly accessibilityService: IAccessibilityService, - @ILogService private readonly logService: ILogService, - @INotebookCellStatusBarService private readonly cellStatusBarService: INotebookCellStatusBarService, + @IConfigurationService private readonly _configurationService: IConfigurationService, + @IEditorService private readonly _editorService: IEditorService, + @IEditorGroupsService private readonly _editorGroupsService: IEditorGroupsService, + @IAccessibilityService private readonly _accessibilityService: IAccessibilityService, + @ILogService private readonly _logService: ILogService, + @INotebookCellStatusBarService private readonly _cellStatusBarService: INotebookCellStatusBarService, @INotebookEditorModelResolverService private readonly _notebookModelResolverService: INotebookEditorModelResolverService, @IUriIdentityService private readonly _uriIdentityService: IUriIdentityService, @IInstantiationService private readonly _instantiationService: IInstantiationService, @@ -339,26 +338,26 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo })); const updateOrder = () => { - let userOrder = this.configurationService.getValue(DisplayOrderKey); + let userOrder = this._configurationService.getValue(DisplayOrderKey); this._proxy.$acceptDisplayOrder({ - defaultOrder: this.accessibilityService.isScreenReaderOptimized() ? ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER : NOTEBOOK_DISPLAY_ORDER, + defaultOrder: this._accessibilityService.isScreenReaderOptimized() ? ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER : NOTEBOOK_DISPLAY_ORDER, userOrder: userOrder }); }; updateOrder(); - this._register(this.configurationService.onDidChangeConfiguration(e => { + this._register(this._configurationService.onDidChangeConfiguration(e => { if (e.affectedKeys.indexOf(DisplayOrderKey) >= 0) { updateOrder(); } })); - this._register(this.accessibilityService.onDidChangeScreenReaderOptimized(() => { + this._register(this._accessibilityService.onDidChangeScreenReaderOptimized(() => { updateOrder(); })); - const activeEditorPane = this.editorService.activeEditorPane as any | undefined; + const activeEditorPane = this._editorService.activeEditorPane as any | undefined; const notebookEditor = activeEditorPane?.isNotebookEditor ? activeEditorPane.getControl() : undefined; this._updateState(notebookEditor); } @@ -371,7 +370,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo }), )); - const activeEditorPane = this.editorService.activeEditorPane as any | undefined; + const activeEditorPane = this._editorService.activeEditorPane as any | undefined; const notebookEditor = activeEditorPane?.isNotebookEditor ? activeEditorPane.getControl() : undefined; this._updateState(notebookEditor); } @@ -391,7 +390,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo private async _updateState(focusedNotebookEditor?: IEditor) { let activeEditor: string | null = null; - const activeEditorPane = this.editorService.activeEditorPane as any | undefined; + const activeEditorPane = this._editorService.activeEditorPane as any | undefined; if (activeEditorPane?.isNotebookEditor) { const notebookEditor = (activeEditorPane.getControl() as INotebookEditor); activeEditor = notebookEditor && notebookEditor.hasModel() ? notebookEditor!.getId() : null; @@ -408,7 +407,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo }); const visibleEditorsMap = new Map(); - this.editorService.visibleEditorPanes.forEach(editor => { + this._editorService.visibleEditorPanes.forEach(editor => { if ((editor as any).isNotebookEditor) { const nbEditorWidget = (editor as any).getControl() as INotebookEditor; if (nbEditorWidget && editors.has(nbEditorWidget.getId())) { @@ -550,15 +549,15 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo preloads: dto.preloads?.map(u => URI.revive(u)), supportedLanguages: dto.supportedLanguages, resolve: (uri: URI, editorId: string, token: CancellationToken): Promise => { - this.logService.debug('MainthreadNotebooks.resolveNotebookKernel', uri.path, dto.friendlyId); + this._logService.debug('MainthreadNotebooks.resolveNotebookKernel', uri.path, dto.friendlyId); return this._proxy.$resolveNotebookKernel(handle, editorId, uri, dto.friendlyId, token); }, executeNotebookCell: (uri: URI, cellHandle: number | undefined): Promise => { - this.logService.debug('MainthreadNotebooks.executeNotebookCell', uri.path, dto.friendlyId, cellHandle); + this._logService.debug('MainthreadNotebooks.executeNotebookCell', uri.path, dto.friendlyId, cellHandle); return this._proxy.$executeNotebookKernelFromProvider(handle, uri, dto.friendlyId, cellHandle); }, cancelNotebookCell: (uri: URI, cellHandle: number | undefined): Promise => { - this.logService.debug('MainthreadNotebooks.cancelNotebookCell', uri.path, dto.friendlyId, cellHandle); + this._logService.debug('MainthreadNotebooks.cancelNotebookCell', uri.path, dto.friendlyId, cellHandle); return this._proxy.$cancelNotebookKernelFromProvider(handle, uri, dto.friendlyId, cellHandle); } }); @@ -654,7 +653,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo if (statusBarEntry.visible) { this._cellStatusBarEntries.set( id, - this.cellStatusBarService.addEntry(statusBarEntry)); + this._cellStatusBarService.addEntry(statusBarEntry)); } } @@ -678,23 +677,23 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo override: false, }; - const columnArg = viewColumnToEditorGroup(this._editorGroupService, options.position); + const columnArg = viewColumnToEditorGroup(this._editorGroupsService, options.position); let group: IEditorGroup | undefined = undefined; if (columnArg === SIDE_GROUP) { - const direction = preferredSideBySideGroupDirection(this.configurationService); + const direction = preferredSideBySideGroupDirection(this._configurationService); - let neighbourGroup = this.editorGroupsService.findGroup({ direction }); + let neighbourGroup = this._editorGroupsService.findGroup({ direction }); if (!neighbourGroup) { - neighbourGroup = this.editorGroupsService.addGroup(this.editorGroupsService.activeGroup, direction); + neighbourGroup = this._editorGroupsService.addGroup(this._editorGroupsService.activeGroup, direction); } group = neighbourGroup; } else { - group = this.editorGroupsService.getGroup(viewColumnToEditorGroup(this.editorGroupsService, columnArg)) ?? this.editorGroupsService.activeGroup; + group = this._editorGroupsService.getGroup(viewColumnToEditorGroup(this._editorGroupsService, columnArg)) ?? this._editorGroupsService.activeGroup; } - const input = this.editorService.createEditorInput({ resource: URI.revive(resource), options: editorOptions }); + const input = this._editorService.createEditorInput({ resource: URI.revive(resource), options: editorOptions }); // TODO: handle options.selection const editorPane = await this._instantiationService.invokeFunction(openEditorWith, input, viewType, options, group); From 781bcaeb500af6ce682a8aaf51e8e6d62ee7bd47 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 05:30:20 -0800 Subject: [PATCH 056/325] Call shutdownAll on ptyService --- src/vs/platform/terminal/common/terminal.ts | 2 ++ .../terminal/electron-browser/localPtyService.ts | 9 ++++++++- src/vs/platform/terminal/node/ptyService.ts | 4 ++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index 7cbace5c596..77295d400e4 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -45,6 +45,8 @@ export interface IPtyService { windowsEnableConpty: boolean ): Promise; + shutdownAll?(): Promise; + start(id: number): Promise; shutdown(id: number, immediate: boolean): Promise; diff --git a/src/vs/platform/terminal/electron-browser/localPtyService.ts b/src/vs/platform/terminal/electron-browser/localPtyService.ts index 8b813aed0c9..dfc72dc3b44 100644 --- a/src/vs/platform/terminal/electron-browser/localPtyService.ts +++ b/src/vs/platform/terminal/electron-browser/localPtyService.ts @@ -68,7 +68,14 @@ export class LocalPtyService extends Disposable implements IPtyService { this._onPtyHostStart.fire(); // Handle exit - this._register({ dispose: () => client.dispose() }); + this._register({ + dispose: () => { + if (proxy.shutdownAll) { + proxy.shutdownAll(); + } + client.dispose(); + } + }); this._register(client.onDidProcessExit(e => { this._onPtyHostExit.fire(e.code); if (!this._isDisposed) { diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index eca137241c4..af4db72adb1 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -60,6 +60,10 @@ export class PtyService extends Disposable implements IPtyService { return id; } + async shutdownAll(): Promise { + this.dispose(); + } + async start(id: number): Promise { return this._throwIfNoPty(id).start(); } From cc0ccaf1c0381952e7b44ba5c0930509c0b13c52 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 12 Feb 2021 14:34:20 +0100 Subject: [PATCH 057/325] more disposing when dispose main thread notebooks, https://github.com/microsoft/vscode/issues/115698 --- src/vs/workbench/api/browser/mainThreadNotebook.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts index 8271fcb3dd4..812b2bed3f4 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -152,6 +152,9 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo item.emitter.dispose(); item.provider.dispose(); } + + dispose(this._editorEventListenersMapping.values()); + dispose(this._documentEventListenersMapping.values()); } async $tryApplyEdits(_viewType: string, resource: UriComponents, modelVersionId: number, cellEdits: ICellEditOperation[]): Promise { From a6be559d52d5bfaa9e423898d37abb0d234ae7d6 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 12 Feb 2021 14:43:34 +0100 Subject: [PATCH 058/325] :lipstick: fyi @rebornix --- .../contrib/notebook/browser/notebookEditorWidget.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 148cb42ef38..cdbd1d7ab6d 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -804,10 +804,6 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor return; } - if (tokenSource.token.isCancellationRequested) { - return; - } - if ((availableKernels.length) > 1) { this._notebookHasMultipleKernels!.set(true); this.multipleKernelsAvailable = true; From 3eefea3b000b530c0c53ade3de117c8d3a3374cd Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 12 Feb 2021 14:44:49 +0100 Subject: [PATCH 059/325] sync enablement keys and service key --- .../platform/userDataSync/common/globalStateSync.ts | 11 ++++++++++- src/vs/platform/userDataSync/common/userDataSync.ts | 7 +++++++ .../common/userDataSyncResourceEnablementService.ts | 13 +------------ .../userDataSync/common/userDataSyncStoreService.ts | 8 ++------ 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/vs/platform/userDataSync/common/globalStateSync.ts b/src/vs/platform/userDataSync/common/globalStateSync.ts index 7c69ad4635a..8561db5aeeb 100644 --- a/src/vs/platform/userDataSync/common/globalStateSync.ts +++ b/src/vs/platform/userDataSync/common/globalStateSync.ts @@ -5,7 +5,7 @@ import { IUserDataSyncStoreService, IUserDataSyncLogService, IGlobalState, SyncResource, IUserDataSynchroniser, IUserDataSyncResourceEnablementService, - IUserDataSyncBackupStoreService, ISyncResourceHandle, IStorageValue, USER_DATA_SYNC_SCHEME, IRemoteUserData, Change + IUserDataSyncBackupStoreService, ISyncResourceHandle, IStorageValue, USER_DATA_SYNC_SCHEME, IRemoteUserData, Change, ALL_SYNC_RESOURCES, getEnablementKey, SYNC_SERVICE_URL_TYPE } from 'vs/platform/userDataSync/common/userDataSync'; import { VSBuffer } from 'vs/base/common/buffer'; import { Event } from 'vs/base/common/event'; @@ -23,6 +23,7 @@ import { format } from 'vs/base/common/jsonFormatter'; import { applyEdits } from 'vs/base/common/jsonEdit'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { CancellationToken } from 'vs/base/common/cancellation'; +import { isWeb } from 'vs/base/common/platform'; const argvStoragePrefx = 'globalState.argv.'; const argvProperties: string[] = ['locale']; @@ -346,6 +347,14 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs const machine = this.storageService.keys(StorageScope.GLOBAL, StorageTarget.MACHINE); const registered = [...user, ...machine]; const unregistered = lastSyncGlobalState?.storage ? Object.keys(lastSyncGlobalState.storage).filter(key => !key.startsWith(argvStoragePrefx) && !registered.includes(key) && this.storageService.get(key, StorageScope.GLOBAL) !== undefined) : []; + + if (!isWeb) { + // Following keys are synced only in web. Do not sync these keys in other platforms + const keysSyncedOnlyInWeb = [...ALL_SYNC_RESOURCES.map(resource => getEnablementKey(resource)), SYNC_SERVICE_URL_TYPE]; + unregistered.push(...keysSyncedOnlyInWeb); + machine.push(...keysSyncedOnlyInWeb); + } + return { user, machine, unregistered }; } } diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index ef13265a4fb..afabfc02f64 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -386,6 +386,13 @@ export interface IUserDataSynchroniser { //#endregion +// #region keys synced only in web + +export const SYNC_SERVICE_URL_TYPE = 'sync.store.url.type'; +export function getEnablementKey(resource: SyncResource) { return `sync.enable.${resource}`; } + +// #endregion + // #region User Data Sync Services export const IUserDataSyncResourceEnablementService = createDecorator('IUserDataSyncResourceEnablementService'); diff --git a/src/vs/platform/userDataSync/common/userDataSyncResourceEnablementService.ts b/src/vs/platform/userDataSync/common/userDataSyncResourceEnablementService.ts index a5c7efb03e1..c96fbad455b 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncResourceEnablementService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncResourceEnablementService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IUserDataSyncResourceEnablementService, ALL_SYNC_RESOURCES, SyncResource } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncResourceEnablementService, ALL_SYNC_RESOURCES, SyncResource, getEnablementKey } from 'vs/platform/userDataSync/common/userDataSync'; import { Disposable } from 'vs/base/common/lifecycle'; import { Emitter, Event } from 'vs/base/common/event'; import { IStorageService, IStorageValueChangeEvent, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; @@ -14,9 +14,6 @@ type SyncEnablementClassification = { enabled?: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; }; -const enablementKey = 'sync.enable'; -function getEnablementKey(resource: SyncResource) { return `${enablementKey}.${resource}`; } - export class UserDataSyncResourceEnablementService extends Disposable implements IUserDataSyncResourceEnablementService { _serviceBrand: any; @@ -30,14 +27,6 @@ export class UserDataSyncResourceEnablementService extends Disposable implements ) { super(); this._register(storageService.onDidChangeValue(e => this.onDidStorageChange(e))); - - for (const resource of ALL_SYNC_RESOURCES) { - const resourceEnablementKey = getEnablementKey(resource); - if (this.storageService.getBoolean(resourceEnablementKey, StorageScope.GLOBAL) === undefined) { - // Make sure the resource enablement storageKey is added to user/machine targets - this.storeResourceEnablement(resourceEnablementKey, true); - } - } } isResourceEnabled(resource: SyncResource): boolean { diff --git a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts index 259a189f0bd..e9454fce235 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable, toDisposable, } from 'vs/base/common/lifecycle'; -import { IUserData, IUserDataSyncStoreService, UserDataSyncErrorCode, IUserDataSyncStore, ServerResource, UserDataSyncStoreError, IUserDataSyncLogService, IUserDataManifest, IResourceRefHandle, HEADER_OPERATION_ID, HEADER_EXECUTION_ID, CONFIGURATION_SYNC_STORE_KEY, IAuthenticationProvider, IUserDataSyncStoreManagementService, UserDataSyncStoreType, IUserDataSyncStoreClient } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserData, IUserDataSyncStoreService, UserDataSyncErrorCode, IUserDataSyncStore, ServerResource, UserDataSyncStoreError, IUserDataSyncLogService, IUserDataManifest, IResourceRefHandle, HEADER_OPERATION_ID, HEADER_EXECUTION_ID, CONFIGURATION_SYNC_STORE_KEY, IAuthenticationProvider, IUserDataSyncStoreManagementService, UserDataSyncStoreType, IUserDataSyncStoreClient, SYNC_SERVICE_URL_TYPE } from 'vs/platform/userDataSync/common/userDataSync'; import { IRequestService, asText, isSuccess as isSuccessContext, asJson } from 'vs/platform/request/common/request'; import { joinPath, relativePath } from 'vs/base/common/resources'; import { CancellationToken } from 'vs/base/common/cancellation'; @@ -23,7 +23,6 @@ import { isString, isObject, isArray } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import { getErrorMessage, isPromiseCanceledError } from 'vs/base/common/errors'; -const SYNC_SERVICE_URL_TYPE = 'sync.store.url.type'; const SYNC_PREVIOUS_STORE = 'sync.previous.store'; const DONOT_MAKE_REQUESTS_UNTIL_KEY = 'sync.donot-make-requests-until'; const USER_SESSION_ID_KEY = 'sync.user-session-id'; @@ -56,9 +55,6 @@ export abstract class AbstractUserDataSyncStoreManagementService extends Disposa ) { super(); this.updateUserDataSyncStore(); - - // Make sure the userDataSyncStore type storageKey is added to user/machine targets - this.userDataSyncStoreType = this.userDataSyncStore?.type; } protected updateUserDataSyncStore(): void { @@ -78,7 +74,7 @@ export abstract class AbstractUserDataSyncStoreManagementService extends Disposa const syncStore = value as ConfigurationSyncStore; const canSwitch = !!syncStore.canSwitch && !configuredStore?.url; const defaultType: UserDataSyncStoreType = syncStore.url === syncStore.insidersUrl ? 'insiders' : 'stable'; - const type: UserDataSyncStoreType = this.userDataSyncStoreType || defaultType; + const type: UserDataSyncStoreType = (canSwitch ? this.userDataSyncStoreType : undefined) || defaultType; const url = configuredStore?.url || (type === 'insiders' ? syncStore.insidersUrl : type === 'stable' ? syncStore.stableUrl From da6a819b54a80c097430ad1ae034531cc607f880 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 12 Feb 2021 15:10:02 +0100 Subject: [PATCH 060/325] Tab lists should only occupy a single tab stop fixes #106438 --- .../browser/ui/actionbar/actionViewItems.ts | 8 +++--- src/vs/base/browser/ui/actionbar/actionbar.ts | 25 +++++++++++++++++-- .../browser/parts/editor/tabsTitleControl.ts | 9 +++++-- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/vs/base/browser/ui/actionbar/actionViewItems.ts b/src/vs/base/browser/ui/actionbar/actionViewItems.ts index b4dafee88bf..3d8ddb9c78c 100644 --- a/src/vs/base/browser/ui/actionbar/actionViewItems.ts +++ b/src/vs/base/browser/ui/actionbar/actionViewItems.ts @@ -181,9 +181,9 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem { } } - setFocusable(): void { + setFocusable(focusable: boolean): void { if (this.element) { - this.element.tabIndex = 0; + this.element.tabIndex = focusable ? 0 : -1; } } @@ -288,9 +288,9 @@ export class ActionViewItem extends BaseActionViewItem { } } - setFocusable(): void { + setFocusable(focusable: boolean): void { if (this.label) { - this.label.tabIndex = 0; + this.label.tabIndex = focusable ? 0 : -1; } } diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index e02edc21588..4ba146296b9 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -63,6 +63,8 @@ export class ActionBar extends Disposable implements IActionRunner { // Trigger Key Tracking private triggerKeyDown: boolean = false; + private focusable: boolean = true; + // Elements domNode: HTMLElement; protected actionsList: HTMLElement; @@ -219,6 +221,25 @@ export class ActionBar extends Disposable implements IActionRunner { } } + // Some action bars should not be focusable at times + // When an action bar is not focusable make sure to make all the elements inside it not focusable + // When an action bar is focusable again, make sure the first enabled item can be focused + setFocusable(focusable: boolean): void { + this.focusable = focusable; + if (this.focusable) { + const firstEnabled = this.viewItems.find(vi => vi instanceof BaseActionViewItem && vi.isEnabled()); + if (firstEnabled instanceof BaseActionViewItem) { + firstEnabled.setFocusable(true); + } + } else { + this.viewItems.forEach(vi => { + if (vi instanceof BaseActionViewItem) { + vi.setFocusable(false); + } + }); + } + } + private isTriggerKeyEvent(event: StandardKeyboardEvent): boolean { let ret = false; this._triggerKeys.keys.forEach(keyCode => { @@ -297,9 +318,9 @@ export class ActionBar extends Disposable implements IActionRunner { item.setActionContext(this.context); item.render(actionViewItemElement); - if (this.viewItems.every(i => !i.isEnabled()) && item instanceof BaseActionViewItem && item.isEnabled()) { + if (this.focusable && this.viewItems.every(i => !i.isEnabled()) && item instanceof BaseActionViewItem && item.isEnabled()) { // We need to allow for the first enabled item to be focused on using tab navigation #106441 - item.setFocusable(); + item.setFocusable(true); } if (index === null || index < 0 || index >= this.actionsList.children.length) { diff --git a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts index d07cc642e0a..7b657de07f4 100644 --- a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts @@ -606,7 +606,6 @@ export class TabsTitleControl extends TitleControl { // Tab Container const tabContainer = document.createElement('div'); tabContainer.draggable = true; - tabContainer.tabIndex = 0; tabContainer.setAttribute('role', 'tab'); tabContainer.classList.add('tab'); @@ -1187,13 +1186,17 @@ export class TabsTitleControl extends TitleControl { } private doRedrawTabActive(isGroupActive: boolean, allowBorderTop: boolean, editor: IEditorInput, tabContainer: HTMLElement, tabLabelWidget: IResourceLabel): void { - + const index = this.group.getIndexOfEditor(editor); + const actionBar = this.tabActionBars[index]; // Tab is active if (this.group.isActive(editor)) { // Container tabContainer.classList.add('active'); tabContainer.setAttribute('aria-selected', 'true'); + // Only active tab can be focused into + tabContainer.tabIndex = 0; + actionBar.setFocusable(true); tabContainer.style.backgroundColor = this.getColor(isGroupActive ? TAB_ACTIVE_BACKGROUND : TAB_UNFOCUSED_ACTIVE_BACKGROUND) || ''; const activeTabBorderColorBottom = this.getColor(isGroupActive ? TAB_ACTIVE_BORDER : TAB_UNFOCUSED_ACTIVE_BORDER); @@ -1224,6 +1227,8 @@ export class TabsTitleControl extends TitleControl { // Container tabContainer.classList.remove('active'); tabContainer.setAttribute('aria-selected', 'false'); + tabContainer.tabIndex = -1; + actionBar.setFocusable(false); tabContainer.style.backgroundColor = this.getColor(isGroupActive ? TAB_INACTIVE_BACKGROUND : TAB_UNFOCUSED_INACTIVE_BACKGROUND) || ''; tabContainer.style.boxShadow = ''; From d88249fdfdaa832a1a9c84abca5f6297c0af6e1e Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 12 Feb 2021 15:11:24 +0100 Subject: [PATCH 061/325] add notebookKernelCount context key, clean up non-null assertions in notebook editor, modernize contributions store --- .../notebook/browser/notebookBrowser.ts | 1 + .../notebook/browser/notebookEditorWidget.ts | 143 ++++++++---------- 2 files changed, 66 insertions(+), 78 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 31b197cb1b6..a67a588bbeb 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -64,6 +64,7 @@ export const NOTEBOOK_CELL_INPUT_COLLAPSED = new RawContextKey('noteboo export const NOTEBOOK_CELL_OUTPUT_COLLAPSED = new RawContextKey('notebookCellOutputIsCollapsed', false); // bool // Kernels export const NOTEBOOK_HAS_MULTIPLE_KERNELS = new RawContextKey('notebookHasMultipleKernels', false); +export const NOTEBOOK_KERNEL_COUNT = new RawContextKey('notebookKernelCount', 0); //#endregion diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index cdbd1d7ab6d..6f8e12d51b9 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -14,7 +14,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { Color, RGBA } from 'vs/base/common/color'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; -import { combinedDisposable, Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { combinedDisposable, Disposable, DisposableStore, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { ScrollEvent } from 'vs/base/common/scrollable'; import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; @@ -41,7 +41,7 @@ import { IEditorMemento } from 'vs/workbench/common/editor'; import { Memento, MementoObject } from 'vs/workbench/common/memento'; import { PANEL_BORDER } from 'vs/workbench/common/theme'; import { BOTTOM_CELL_TOOLBAR_GAP, BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_BOTTOM_MARGIN, CELL_MARGIN, CELL_OUTPUT_PADDING, CELL_RUN_GUTTER, CELL_TOP_MARGIN, CODE_CELL_LEFT_MARGIN, COLLAPSED_INDICATOR_HEIGHT, SCROLLABLE_ELEMENT_PADDING_TOP } from 'vs/workbench/contrib/notebook/browser/constants'; -import { CellEditState, CellFocusMode, IActiveNotebookEditor, ICellOutputViewModel, ICellViewModel, ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel, IInsetRenderOutput, INotebookCellList, INotebookCellOutputLayoutInfo, INotebookDeltaDecoration, INotebookEditor, INotebookEditorContribution, INotebookEditorContributionDescription, INotebookEditorCreationOptions, INotebookEditorMouseEvent, NotebookEditorOptions, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_RUNNABLE, NOTEBOOK_HAS_MULTIPLE_KERNELS, NOTEBOOK_OUTPUT_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellEditState, CellFocusMode, IActiveNotebookEditor, ICellOutputViewModel, ICellViewModel, ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel, IInsetRenderOutput, INotebookCellList, INotebookCellOutputLayoutInfo, INotebookDeltaDecoration, INotebookEditor, INotebookEditorContribution, INotebookEditorContributionDescription, INotebookEditorCreationOptions, INotebookEditorMouseEvent, NotebookEditorOptions, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_RUNNABLE, NOTEBOOK_HAS_MULTIPLE_KERNELS, NOTEBOOK_KERNEL_COUNT, NOTEBOOK_OUTPUT_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NotebookEditorExtensionsRegistry } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions'; import { NotebookKernelProviderAssociation, NotebookKernelProviderAssociations, notebookKernelProviderAssociationsSettingId } from 'vs/workbench/contrib/notebook/browser/notebookKernelAssociation'; import { NotebookCellList } from 'vs/workbench/contrib/notebook/browser/view/notebookCellList'; @@ -92,14 +92,16 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor private _dimension: DOM.Dimension | null = null; private _shadowElementViewInfo: { height: number, width: number, top: number; left: number; } | null = null; - private _editorFocus: IContextKey | null = null; - private _outputFocus: IContextKey | null = null; - private _editorEditable: IContextKey | null = null; - private _editorRunnable: IContextKey | null = null; - private _notebookExecuting: IContextKey | null = null; - private _notebookHasMultipleKernels: IContextKey | null = null; + private readonly _editorFocus: IContextKey; + private readonly _outputFocus: IContextKey; + private readonly _editorEditable: IContextKey; + private readonly _editorRunnable: IContextKey; + private readonly _notebookExecuting: IContextKey; + private readonly _notebookHasMultipleKernels: IContextKey; + private readonly _notebookKernelCount: IContextKey; + private _outputRenderer: OutputRenderer; - protected readonly _contributions: { [key: string]: INotebookEditorContribution; }; + protected readonly _contributions = new Map(); private _scrollBeyondLastLine: boolean; private readonly _memento: Memento; private readonly _activeKernelMemento: Memento; @@ -272,7 +274,6 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor this._activeKernelMemento = new Memento(NotebookEditorActiveKernelCache, storageService); this._outputRenderer = new OutputRenderer(this, this.instantiationService); - this._contributions = {}; this._scrollBeyondLastLine = this.configurationService.getValue('editor.scrollBeyondLastLine'); this.configurationService.onDidChangeConfiguration(e => { @@ -289,7 +290,41 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor }); this.notebookService.addNotebookEditor(this); - this._createEditor(); + + const id = generateUuid(); + this._overlayContainer.id = `notebook-${id}`; + this._overlayContainer.className = 'notebookOverlay'; + this._overlayContainer.classList.add('notebook-editor'); + this._overlayContainer.style.visibility = 'hidden'; + + this.layoutService.container.appendChild(this._overlayContainer); + this._createBody(this._overlayContainer); + this._generateFontInfo(); + this._isVisible = true; + this._editorFocus = NOTEBOOK_EDITOR_FOCUSED.bindTo(this.scopedContextKeyService); + this._outputFocus = NOTEBOOK_OUTPUT_FOCUSED.bindTo(this.scopedContextKeyService); + this._editorEditable = NOTEBOOK_EDITOR_EDITABLE.bindTo(this.scopedContextKeyService); + this._editorRunnable = NOTEBOOK_EDITOR_RUNNABLE.bindTo(this.scopedContextKeyService); + this._notebookExecuting = NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK.bindTo(this.scopedContextKeyService); + this._notebookHasMultipleKernels = NOTEBOOK_HAS_MULTIPLE_KERNELS.bindTo(this.scopedContextKeyService); + this._notebookKernelCount = NOTEBOOK_KERNEL_COUNT.bindTo(this.scopedContextKeyService); + + let contributions: INotebookEditorContributionDescription[]; + if (Array.isArray(this.creationOptions.contributions)) { + contributions = this.creationOptions.contributions; + } else { + contributions = NotebookEditorExtensionsRegistry.getEditorContributions(); + } + for (const desc of contributions) { + try { + const contribution = this.instantiationService.createInstance(desc.ctor, this); + this._contributions.set(desc.id, contribution); + } catch (err) { + onUnexpectedError(err); + } + } + + this._updateForNotebookConfiguration(); } /** @@ -359,12 +394,12 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor // Note - focus going to the webview will fire 'blur', but the webview element will be // a descendent of the notebook editor root. const focused = DOM.isAncestor(document.activeElement, this._overlayContainer); - this._editorFocus?.set(focused); + this._editorFocus.set(focused); this.viewModel?.setFocus(focused); } hasFocus() { - return this._editorFocus?.get() || false; + return this._editorFocus.get() || false; } hasWebviewFocus() { @@ -405,46 +440,6 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor return false; } - private _createEditor(): void { - const id = generateUuid(); - this._overlayContainer.id = `notebook-${id}`; - this._overlayContainer.className = 'notebookOverlay'; - this._overlayContainer.classList.add('notebook-editor'); - this._overlayContainer.style.visibility = 'hidden'; - - this.layoutService.container.appendChild(this._overlayContainer); - this._createBody(this._overlayContainer); - this._generateFontInfo(); - this._editorFocus = NOTEBOOK_EDITOR_FOCUSED.bindTo(this.scopedContextKeyService); - this._isVisible = true; - this._outputFocus = NOTEBOOK_OUTPUT_FOCUSED.bindTo(this.scopedContextKeyService); - this._editorEditable = NOTEBOOK_EDITOR_EDITABLE.bindTo(this.scopedContextKeyService); - this._editorEditable.set(true); - this._editorRunnable = NOTEBOOK_EDITOR_RUNNABLE.bindTo(this.scopedContextKeyService); - this._editorRunnable.set(true); - this._notebookExecuting = NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK.bindTo(this.scopedContextKeyService); - this._notebookHasMultipleKernels = NOTEBOOK_HAS_MULTIPLE_KERNELS.bindTo(this.scopedContextKeyService); - this._notebookHasMultipleKernels.set(false); - - let contributions: INotebookEditorContributionDescription[]; - if (Array.isArray(this.creationOptions.contributions)) { - contributions = this.creationOptions.contributions; - } else { - contributions = NotebookEditorExtensionsRegistry.getEditorContributions(); - } - - for (const desc of contributions) { - try { - const contribution = this.instantiationService.createInstance(desc.ctor, this); - this._contributions[desc.id] = contribution; - } catch (err) { - onUnexpectedError(err); - } - } - - this._updateForNotebookConfiguration(); - } - private _generateFontInfo(): void { const editorOptions = this.configurationService.getValue('editor'); this._fontInfo = BareFontInfo.createFromRawSettings(editorOptions, getZoomLevel(), getPixelRatio()); @@ -630,7 +625,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor onWillHide() { this._isVisible = false; - this._editorFocus?.set(false); + this._editorFocus.set(false); this._overlayContainer.style.visibility = 'hidden'; this._overlayContainer.style.left = '-50000px'; } @@ -641,7 +636,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor focus() { this._isVisible = true; - this._editorFocus?.set(true); + this._editorFocus.set(true); if (this._webiewFocused) { this._webview?.focusWebview(); @@ -804,11 +799,12 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor return; } - if ((availableKernels.length) > 1) { - this._notebookHasMultipleKernels!.set(true); + this._notebookKernelCount.set(availableKernels.length); + if (availableKernels.length > 1) { + this._notebookHasMultipleKernels.set(true); this.multipleKernelsAvailable = true; } else { - this._notebookHasMultipleKernels!.set(false); + this._notebookHasMultipleKernels.set(false); this.multipleKernelsAvailable = false; } @@ -927,12 +923,12 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor } const notebookMetadata = this.viewModel.metadata; - this._editorEditable?.set(!!notebookMetadata?.editable); - this._editorRunnable?.set(this.viewModel.runnable); + this._editorEditable.set(!!notebookMetadata?.editable); + this._editorRunnable.set(this.viewModel.runnable); this._overflowContainer.classList.toggle('notebook-editor-editable', !!notebookMetadata?.editable); this.getDomNode().classList.toggle('notebook-editor-editable', !!notebookMetadata?.editable); - this._notebookExecuting?.set(notebookMetadata.runState === NotebookRunState.Running); + this._notebookExecuting.set(notebookMetadata.runState === NotebookRunState.Running); } private async _resolveWebview(): Promise | null> { @@ -964,7 +960,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor } this._webview.webview.onDidBlur(() => { - this._outputFocus?.set(false); + this._outputFocus.set(false); this.updateEditorFocus(); if (this._overlayContainer.contains(document.activeElement)) { @@ -972,7 +968,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor } }); this._webview.webview.onDidFocus(() => { - this._outputFocus?.set(true); + this._outputFocus.set(true); this.updateEditorFocus(); this._onDidFocusEmitter.fire(); @@ -1037,10 +1033,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor // contribution state restore const contributionsState = viewState?.contributionsState || {}; - const keys = Object.keys(this._contributions); - for (let i = 0, len = keys.length; i < len; i++) { - const id = keys[i]; - const contribution = this._contributions[id]; + for (const [id, contribution] of this._contributions) { if (typeof contribution.restoreViewState === 'function') { contribution.restoreViewState(contributionsState[id]); } @@ -1215,10 +1208,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor // Save contribution view states const contributionsState: { [key: string]: unknown } = {}; - - const keys = Object.keys(this._contributions); - for (const id of keys) { - const contribution = this._contributions[id]; + for (const [id, contribution] of this._contributions) { if (typeof contribution.saveViewState === 'function') { contributionsState[id] = contribution.saveViewState(); } @@ -2142,8 +2132,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor //#endregion //#region Editor Contributions - public getContribution(id: string): T { - return (this._contributions[id] || null); + getContribution(id: string): T { + return (this._contributions.get(id) || null); } //#endregion @@ -2155,11 +2145,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor this._webview?.dispose(); this.notebookService.removeNotebookEditor(this); - const keys = Object.keys(this._contributions); - for (let i = 0, len = keys.length; i < len; i++) { - const contributionId = keys[i]; - this._contributions[contributionId].dispose(); - } + dispose(this._contributions.values()); + this._contributions.clear(); this._localStore.clear(); this._list.dispose(); From 93da15934d5bc32a5c295be5349f8e22f610bf07 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Fri, 12 Feb 2021 15:24:45 +0100 Subject: [PATCH 062/325] Improve storage key for stored tunnels --- .../workbench/services/remote/common/remoteExplorerService.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/services/remote/common/remoteExplorerService.ts b/src/vs/workbench/services/remote/common/remoteExplorerService.ts index e066dffffef..1ced7e337bf 100644 --- a/src/vs/workbench/services/remote/common/remoteExplorerService.ts +++ b/src/vs/workbench/services/remote/common/remoteExplorerService.ts @@ -17,6 +17,7 @@ import { IAddressProvider } from 'vs/platform/remote/common/remoteAgentConnectio import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { isNumber, isObject, isString } from 'vs/base/common/types'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { hash } from 'vs/base/common/hash'; export const IRemoteExplorerService = createDecorator('remoteExplorerService'); export const REMOTE_EXPLORER_TYPE_KEY: string = 'remote.explorerType'; @@ -323,7 +324,8 @@ export class TunnelModel extends Disposable { private async getStorageKey(): Promise { const workspace = this.workspaceContextService.getWorkspace(); - return `${TUNNELS_TO_RESTORE}.${this.environmentService.remoteAuthority}.${workspace.id}`; + const workspaceHash = workspace.configuration ? hash(workspace.configuration.path) : (workspace.folders.length > 0 ? hash(workspace.folders[0].uri.path) : undefined); + return `${TUNNELS_TO_RESTORE}.${this.environmentService.remoteAuthority}.${workspaceHash}`; } private async getTunnelRestoreValue(): Promise { From 138cfd777be5f8d184586af413824bb8f7342b25 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 06:26:07 -0800 Subject: [PATCH 063/325] Don't double dispose LocalPtyService --- src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 4cf30b923fd..8081fa4f3de 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -266,7 +266,6 @@ class SharedProcessMain extends Disposable { // Terminal const localPtyService = this._register(new LocalPtyService(logService)); services.set(ILocalPtyService, localPtyService); - this._register(toDisposable(() => localPtyService.dispose())); return new InstantiationService(services); } From a56ce22cedd881f83e623c30a8c132193dbfafc4 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 06:28:08 -0800 Subject: [PATCH 064/325] Disable ptyHost restart --- .../electron-browser/localPtyService.ts | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/vs/platform/terminal/electron-browser/localPtyService.ts b/src/vs/platform/terminal/electron-browser/localPtyService.ts index dfc72dc3b44..e39be645dc7 100644 --- a/src/vs/platform/terminal/electron-browser/localPtyService.ts +++ b/src/vs/platform/terminal/electron-browser/localPtyService.ts @@ -13,9 +13,9 @@ import { IProcessEnvironment } from 'vs/base/common/platform'; import { Emitter } from 'vs/base/common/event'; import { LogLevelChannelClient } from 'vs/platform/log/common/logIpc'; -enum Constants { - MaxRestarts = 5 -} +// enum Constants { +// MaxRestarts = 5 +// } export class LocalPtyService extends Disposable implements IPtyService { declare readonly _serviceBrand: undefined; @@ -23,8 +23,8 @@ export class LocalPtyService extends Disposable implements IPtyService { // ProxyChannel is not used here because events get lost when forwarding across multiple proxies private _proxy: IPtyService; - private _restartCount = 0; - private _isDisposed = false; + // private _restartCount = 0; + // private _isDisposed = false; private readonly _onPtyHostExit = this._register(new Emitter()); readonly onPtyHostExit = this._onPtyHostExit.event; @@ -78,15 +78,15 @@ export class LocalPtyService extends Disposable implements IPtyService { }); this._register(client.onDidProcessExit(e => { this._onPtyHostExit.fire(e.code); - if (!this._isDisposed) { - if (this._restartCount <= Constants.MaxRestarts) { - this._logService.error(`ptyHost terminated unexpectedly with code ${e.code}`); - this._restartCount++; - this._proxy = this._startPtyHost(); - } else { - this._logService.error(`ptyHost terminated unexpectedly with code ${e.code}, giving up`); - } - } + // if (!this._isDisposed) { + // if (this._restartCount <= Constants.MaxRestarts) { + // this._logService.error(`ptyHost terminated unexpectedly with code ${e.code}`); + // this._restartCount++; + // this._proxy = this._startPtyHost(); + // } else { + // this._logService.error(`ptyHost terminated unexpectedly with code ${e.code}, giving up`); + // } + // } })); // Setup logging @@ -107,7 +107,7 @@ export class LocalPtyService extends Disposable implements IPtyService { } dispose() { - this._isDisposed = true; + // this._isDisposed = true; super.dispose(); } From 13d51e7c21e42cf03638e1b2075443f595ca4b8e Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 12 Feb 2021 15:34:11 +0100 Subject: [PATCH 065/325] actionBar: use up/down as well to move focus --- src/vs/base/browser/ui/actionbar/actionbar.ts | 18 +++++++++--------- src/vs/base/browser/ui/menu/menu.ts | 1 + .../parts/activitybar/activitybarPart.ts | 3 +-- src/vs/workbench/browser/parts/compositeBar.ts | 1 - 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index 4ba146296b9..45afd63c40a 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -35,7 +35,7 @@ export interface IActionBarOptions { readonly triggerKeys?: ActionTrigger; readonly allowContextMenu?: boolean; readonly preventLoopNavigation?: boolean; - readonly ignoreOrientationForPreviousAndNextKey?: boolean; + readonly respectOrientationForPreviousAndNextKey?: boolean; } export interface IActionOptions extends IActionViewItemOptions { @@ -119,22 +119,22 @@ export class ActionBar extends Disposable implements IActionRunner { switch (this._orientation) { case ActionsOrientation.HORIZONTAL: - previousKeys = this.options.ignoreOrientationForPreviousAndNextKey ? [KeyCode.LeftArrow, KeyCode.UpArrow] : [KeyCode.LeftArrow]; - nextKeys = this.options.ignoreOrientationForPreviousAndNextKey ? [KeyCode.RightArrow, KeyCode.DownArrow] : [KeyCode.RightArrow]; + previousKeys = this.options.respectOrientationForPreviousAndNextKey ? [KeyCode.LeftArrow] : [KeyCode.LeftArrow, KeyCode.UpArrow]; + nextKeys = this.options.respectOrientationForPreviousAndNextKey ? [KeyCode.RightArrow] : [KeyCode.RightArrow, KeyCode.DownArrow]; break; case ActionsOrientation.HORIZONTAL_REVERSE: - previousKeys = this.options.ignoreOrientationForPreviousAndNextKey ? [KeyCode.RightArrow, KeyCode.DownArrow] : [KeyCode.RightArrow]; - nextKeys = this.options.ignoreOrientationForPreviousAndNextKey ? [KeyCode.LeftArrow, KeyCode.UpArrow] : [KeyCode.LeftArrow]; + previousKeys = this.options.respectOrientationForPreviousAndNextKey ? [KeyCode.RightArrow] : [KeyCode.RightArrow, KeyCode.DownArrow]; + nextKeys = this.options.respectOrientationForPreviousAndNextKey ? [KeyCode.LeftArrow] : [KeyCode.LeftArrow, KeyCode.UpArrow]; this.domNode.className += ' reverse'; break; case ActionsOrientation.VERTICAL: - previousKeys = this.options.ignoreOrientationForPreviousAndNextKey ? [KeyCode.LeftArrow, KeyCode.UpArrow] : [KeyCode.UpArrow]; - nextKeys = this.options.ignoreOrientationForPreviousAndNextKey ? [KeyCode.RightArrow, KeyCode.DownArrow] : [KeyCode.DownArrow]; + previousKeys = this.options.respectOrientationForPreviousAndNextKey ? [KeyCode.UpArrow] : [KeyCode.LeftArrow, KeyCode.UpArrow]; + nextKeys = this.options.respectOrientationForPreviousAndNextKey ? [KeyCode.DownArrow] : [KeyCode.RightArrow, KeyCode.DownArrow]; this.domNode.className += ' vertical'; break; case ActionsOrientation.VERTICAL_REVERSE: - previousKeys = this.options.ignoreOrientationForPreviousAndNextKey ? [KeyCode.RightArrow, KeyCode.DownArrow] : [KeyCode.DownArrow]; - nextKeys = this.options.ignoreOrientationForPreviousAndNextKey ? [KeyCode.LeftArrow, KeyCode.UpArrow] : [KeyCode.UpArrow]; + previousKeys = this.options.respectOrientationForPreviousAndNextKey ? [KeyCode.DownArrow] : [KeyCode.RightArrow, KeyCode.DownArrow]; + nextKeys = this.options.respectOrientationForPreviousAndNextKey ? [KeyCode.UpArrow] : [KeyCode.LeftArrow, KeyCode.UpArrow]; this.domNode.className += ' vertical reverse'; break; } diff --git a/src/vs/base/browser/ui/menu/menu.ts b/src/vs/base/browser/ui/menu/menu.ts index 947ba2708b0..b94c9c99ac2 100644 --- a/src/vs/base/browser/ui/menu/menu.ts +++ b/src/vs/base/browser/ui/menu/menu.ts @@ -86,6 +86,7 @@ export class Menu extends ActionBar { context: options.context, actionRunner: options.actionRunner, ariaLabel: options.ariaLabel, + respectOrientationForPreviousAndNextKey: true, triggerKeys: { keys: [KeyCode.Enter, ...(isMacintosh || isLinux ? [KeyCode.Space] : [])], keyDown: true } }); diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index ba37e0b668f..f9ee130df8c 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -534,8 +534,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { orientation: ActionsOrientation.VERTICAL, ariaLabel: localize('manage', "Manage"), animated: false, - preventLoopNavigation: true, - ignoreOrientationForPreviousAndNextKey: true + preventLoopNavigation: true })); this.globalActivityAction = this._register(new ActivityAction({ diff --git a/src/vs/workbench/browser/parts/compositeBar.ts b/src/vs/workbench/browser/parts/compositeBar.ts index 70d629fb2c0..94fccfcb646 100644 --- a/src/vs/workbench/browser/parts/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositeBar.ts @@ -227,7 +227,6 @@ export class CompositeBar extends Widget implements ICompositeBar { ariaLabel: nls.localize('activityBarAriaLabel', "Active View Switcher"), animated: false, preventLoopNavigation: this.options.preventLoopNavigation, - ignoreOrientationForPreviousAndNextKey: true, triggerKeys: { keyDown: true } })); From 4e1b20a7d5bb377fcd3537d3752851bcc5674db9 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 06:37:48 -0800 Subject: [PATCH 066/325] Log process tree after test suites --- scripts/test-integration.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index b1d5e9588e3..610759621b6 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -55,9 +55,15 @@ else fi if [ -z "$INTEGRATION_TEST_APP_NAME" ]; then - after_suite() { true; } + after_suite() { + true; + ps -aef --forest; + } else - after_suite() { killall $INTEGRATION_TEST_APP_NAME || true; } + after_suite() { + killall $INTEGRATION_TEST_APP_NAME || true; + ps -aef --forest; + } fi # Integration tests in AMD From 6a698d7d435466f13dff1b9852e95954a91c87f4 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 12 Feb 2021 15:42:52 +0100 Subject: [PATCH 067/325] tabs - no need to lookup editor index fyi @isidorn --- .../browser/parts/editor/tabsTitleControl.ts | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts index 7b657de07f4..850294ee6a0 100644 --- a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts @@ -509,8 +509,8 @@ export class TabsTitleControl extends TitleControl { setActive(isGroupActive: boolean): void { // Activity has an impact on each tab's active indication - this.forEachTab((editor, index, tabContainer, tabLabelWidget, tabLabel) => { - this.redrawTabActiveAndDirty(isGroupActive, editor, tabContainer, tabLabelWidget); + this.forEachTab((editor, index, tabContainer, tabLabelWidget, tabLabel, tabActionBar) => { + this.redrawTabActiveAndDirty(isGroupActive, editor, tabContainer, tabActionBar); }); // Activity has an impact on the toolbar, so we need to update and layout @@ -545,7 +545,7 @@ export class TabsTitleControl extends TitleControl { } updateEditorDirty(editor: IEditorInput): void { - this.withTab(editor, (editor, index, tabContainer, tabLabelWidget) => this.redrawTabActiveAndDirty(this.accessor.activeGroup === this.group, editor, tabContainer, tabLabelWidget)); + this.withTab(editor, (editor, index, tabContainer, tabLabelWidget, tabLabel, tabActionBar) => this.redrawTabActiveAndDirty(this.accessor.activeGroup === this.group, editor, tabContainer, tabActionBar)); } updateOptions(oldOptions: IEditorPartOptions, newOptions: IEditorPartOptions): void { @@ -1119,7 +1119,7 @@ export class TabsTitleControl extends TitleControl { this.redrawTabBorders(index, tabContainer); // Active / dirty state - this.redrawTabActiveAndDirty(this.accessor.activeGroup === this.group, editor, tabContainer, tabLabelWidget); + this.redrawTabActiveAndDirty(this.accessor.activeGroup === this.group, editor, tabContainer, tabActionBar); } private redrawTabLabel(editor: IEditorInput, index: number, tabContainer: HTMLElement, tabLabelWidget: IResourceLabel, tabLabel: IEditorInputLabel): void { @@ -1177,26 +1177,23 @@ export class TabsTitleControl extends TitleControl { } } - private redrawTabActiveAndDirty(isGroupActive: boolean, editor: IEditorInput, tabContainer: HTMLElement, tabLabelWidget: IResourceLabel): void { + private redrawTabActiveAndDirty(isGroupActive: boolean, editor: IEditorInput, tabContainer: HTMLElement, tabActionBar: ActionBar): void { const isTabActive = this.group.isActive(editor); const hasModifiedBorderTop = this.doRedrawTabDirty(isGroupActive, isTabActive, editor, tabContainer); - this.doRedrawTabActive(isGroupActive, !hasModifiedBorderTop, editor, tabContainer, tabLabelWidget); + this.doRedrawTabActive(isGroupActive, !hasModifiedBorderTop, editor, tabContainer, tabActionBar); } - private doRedrawTabActive(isGroupActive: boolean, allowBorderTop: boolean, editor: IEditorInput, tabContainer: HTMLElement, tabLabelWidget: IResourceLabel): void { - const index = this.group.getIndexOfEditor(editor); - const actionBar = this.tabActionBars[index]; + private doRedrawTabActive(isGroupActive: boolean, allowBorderTop: boolean, editor: IEditorInput, tabContainer: HTMLElement, tabActionBar: ActionBar): void { + // Tab is active if (this.group.isActive(editor)) { // Container tabContainer.classList.add('active'); tabContainer.setAttribute('aria-selected', 'true'); - // Only active tab can be focused into - tabContainer.tabIndex = 0; - actionBar.setFocusable(true); + tabContainer.tabIndex = 0; // Only active tab can be focused into tabContainer.style.backgroundColor = this.getColor(isGroupActive ? TAB_ACTIVE_BACKGROUND : TAB_UNFOCUSED_ACTIVE_BACKGROUND) || ''; const activeTabBorderColorBottom = this.getColor(isGroupActive ? TAB_ACTIVE_BORDER : TAB_UNFOCUSED_ACTIVE_BORDER); @@ -1219,6 +1216,9 @@ export class TabsTitleControl extends TitleControl { // Label tabContainer.style.color = this.getColor(isGroupActive ? TAB_ACTIVE_FOREGROUND : TAB_UNFOCUSED_ACTIVE_FOREGROUND) || ''; + + // Actions + tabActionBar.setFocusable(true); } // Tab is inactive @@ -1227,13 +1227,15 @@ export class TabsTitleControl extends TitleControl { // Container tabContainer.classList.remove('active'); tabContainer.setAttribute('aria-selected', 'false'); - tabContainer.tabIndex = -1; - actionBar.setFocusable(false); + tabContainer.tabIndex = -1; // Only active tab can be focused into tabContainer.style.backgroundColor = this.getColor(isGroupActive ? TAB_INACTIVE_BACKGROUND : TAB_UNFOCUSED_INACTIVE_BACKGROUND) || ''; tabContainer.style.boxShadow = ''; // Label tabContainer.style.color = this.getColor(isGroupActive ? TAB_INACTIVE_FOREGROUND : TAB_UNFOCUSED_INACTIVE_FOREGROUND) || ''; + + // Actions + tabActionBar.setFocusable(false); } } From 41339cc2a0844f97315a746b89022d7b51477432 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 12 Feb 2021 15:49:15 +0100 Subject: [PATCH 068/325] Make user data path a AMD/CommonJS compatible thing (#116530) * debt - move paths.js into base * add a test * get rid of @ts-ignore * trigger a change * isolate scripts with self invoking function --- build/gulpfile.vscode.js | 2 +- src/main.js | 12 +- src/paths.js | 48 -- src/vs/base/node/languagePacks.js | 453 +++++++++--------- src/vs/base/node/userDataPath.d.ts | 9 + src/vs/base/node/userDataPath.js | 72 +++ .../node/userDataPath.test.ts} | 12 +- .../sharedProcess/sharedProcess.js | 5 +- .../electron-browser/workbench/workbench.js | 5 +- .../electron-sandbox/issue/issueReporter.js | 4 +- .../processExplorer/processExplorer.js | 4 +- .../electron-sandbox/workbench/workbench.js | 6 +- .../environment/node/environmentService.ts | 68 +-- .../platform/product/common/productService.ts | 2 +- 14 files changed, 369 insertions(+), 333 deletions(-) delete mode 100644 src/paths.js create mode 100644 src/vs/base/node/userDataPath.d.ts create mode 100644 src/vs/base/node/userDataPath.js rename src/vs/base/{node/paths.ts => test/node/userDataPath.test.ts} (56%) diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 6d3a369082a..33af8a45375 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -52,13 +52,13 @@ const vscodeResources = [ 'out-build/bootstrap-amd.js', 'out-build/bootstrap-node.js', 'out-build/bootstrap-window.js', - 'out-build/paths.js', 'out-build/vs/**/*.{svg,png,html,jpg}', '!out-build/vs/code/browser/**/*.html', '!out-build/vs/editor/standalone/**/*.svg', 'out-build/vs/base/common/performance.js', 'out-build/vs/base/node/languagePacks.js', 'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh,ps.sh}', + 'out-build/vs/base/node/userDataPath.js', 'out-build/vs/base/browser/ui/codicons/codicon/**', 'out-build/vs/base/parts/sandbox/electron-browser/preload.js', 'out-build/vs/workbench/browser/media/*-theme.css', diff --git a/src/main.js b/src/main.js index 0541fb4c4a0..2584223e1d6 100644 --- a/src/main.js +++ b/src/main.js @@ -9,14 +9,14 @@ const perf = require('./vs/base/common/performance'); perf.mark('code/didStartMain'); -const lp = require('./vs/base/node/languagePacks'); const path = require('path'); const fs = require('fs'); const os = require('os'); +const { getNLSConfiguration } = require('./vs/base/node/languagePacks'); const bootstrap = require('./bootstrap'); const bootstrapNode = require('./bootstrap-node'); -const paths = require('./paths'); -/** @type {Partial & { applicationName: string}} */ +const { getDefaultUserDataPath } = require('./vs/base/node/userDataPath'); +/** @type {Partial} */ const product = require('../product.json'); const { app, protocol, crashReporter } = require('electron'); @@ -84,7 +84,7 @@ let nlsConfigurationPromise = undefined; const metaDataFile = path.join(__dirname, 'nls.metadata.json'); const locale = getUserDefinedLocale(argvConfig); if (locale) { - nlsConfigurationPromise = lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, locale); + nlsConfigurationPromise = getNLSConfiguration(product.commit, userDataPath, metaDataFile, locale); } // Load our code once ready @@ -405,7 +405,7 @@ function getUserDataPath(cliArgs) { return path.join(portable.portableDataPath, 'user-data'); } - return path.resolve(cliArgs['user-data-dir'] || paths.getDefaultUserDataPath()); + return path.resolve(cliArgs['user-data-dir'] || getDefaultUserDataPath()); } /** @@ -560,7 +560,7 @@ async function resolveNlsConfiguration() { // See above the comment about the loader and case sensitiviness appLocale = appLocale.toLowerCase(); - nlsConfiguration = await lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, appLocale); + nlsConfiguration = await getNLSConfiguration(product.commit, userDataPath, metaDataFile, appLocale); if (!nlsConfiguration) { nlsConfiguration = { locale: appLocale, availableLanguages: {} }; } diff --git a/src/paths.js b/src/paths.js deleted file mode 100644 index 2042123d726..00000000000 --- a/src/paths.js +++ /dev/null @@ -1,48 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -//@ts-check -'use strict'; - -const pkg = require('../package.json'); -const path = require('path'); -const os = require('os'); - -/** - * @returns {string} - */ -function getDefaultUserDataPath() { - - // Support global VSCODE_APPDATA environment variable - let appDataPath = process.env['VSCODE_APPDATA']; - - // Otherwise check per platform - if (!appDataPath) { - switch (process.platform) { - case 'win32': - appDataPath = process.env['APPDATA']; - if (!appDataPath) { - const userProfile = process.env['USERPROFILE']; - if (typeof userProfile !== 'string') { - throw new Error('Windows: Unexpected undefined %USERPROFILE% environment variable'); - } - appDataPath = path.join(userProfile, 'AppData', 'Roaming'); - } - break; - case 'darwin': - appDataPath = path.join(os.homedir(), 'Library', 'Application Support'); - break; - case 'linux': - appDataPath = process.env['XDG_CONFIG_HOME'] || path.join(os.homedir(), '.config'); - break; - default: - throw new Error('Platform not supported'); - } - } - - return path.join(appDataPath, pkg.name); -} - -exports.getDefaultUserDataPath = getDefaultUserDataPath; diff --git a/src/vs/base/node/languagePacks.js b/src/vs/base/node/languagePacks.js index f47191157c1..5c14fade878 100644 --- a/src/vs/base/node/languagePacks.js +++ b/src/vs/base/node/languagePacks.js @@ -3,256 +3,257 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +/// + //@ts-check -'use strict'; - -/** - * @param {NodeRequire} nodeRequire - * @param {typeof import('path')} path - * @param {typeof import('fs')} fs - * @param {typeof import('../common/performance')} perf - */ -function factory(nodeRequire, path, fs, perf) { +(function () { + 'use strict'; /** - * @param {string} file - * @returns {Promise} + * @param {NodeRequire} nodeRequire + * @param {typeof import('path')} path + * @param {typeof import('fs')} fs + * @param {typeof import('../common/performance')} perf */ - function exists(file) { - return new Promise(c => fs.exists(file, c)); - } + function factory(nodeRequire, path, fs, perf) { - /** - * @param {string} file - * @returns {Promise} - */ - function touch(file) { - return new Promise((c, e) => { const d = new Date(); fs.utimes(file, d, d, err => err ? e(err) : c()); }); - } - - /** - * @param {string} dir - * @returns {Promise} - */ - function mkdirp(dir) { - return new Promise((c, e) => fs.mkdir(dir, { recursive: true }, err => (err && err.code !== 'EEXIST') ? e(err) : c(dir))); - } - - /** - * @param {string} location - * @returns {Promise} - */ - function rimraf(location) { - return new Promise((c, e) => fs.rmdir(location, { recursive: true }, err => (err && err.code !== 'ENOENT') ? e(err) : c())); - } - - /** - * @param {string} file - * @returns {Promise} - */ - function readFile(file) { - return new Promise((c, e) => fs.readFile(file, 'utf8', (err, data) => err ? e(err) : c(data))); - } - - /** - * @param {string} file - * @param {string} content - * @returns {Promise} - */ - function writeFile(file, content) { - return new Promise((c, e) => fs.writeFile(file, content, 'utf8', err => err ? e(err) : c())); - } - - /** - * @param {string} userDataPath - * @returns {object} - */ - function getLanguagePackConfigurations(userDataPath) { - const configFile = path.join(userDataPath, 'languagepacks.json'); - try { - return nodeRequire(configFile); - } catch (err) { - // Do nothing. If we can't read the file we have no - // language pack config. + /** + * @param {string} file + * @returns {Promise} + */ + function exists(file) { + return new Promise(c => fs.exists(file, c)); } - return undefined; - } - /** - * @param {object} config - * @param {string} locale - */ - function resolveLanguagePackLocale(config, locale) { - try { - while (locale) { - if (config[locale]) { - return locale; - } else { - const index = locale.lastIndexOf('-'); - if (index > 0) { - locale = locale.substring(0, index); + /** + * @param {string} file + * @returns {Promise} + */ + function touch(file) { + return new Promise((c, e) => { const d = new Date(); fs.utimes(file, d, d, err => err ? e(err) : c()); }); + } + + /** + * @param {string} dir + * @returns {Promise} + */ + function mkdirp(dir) { + return new Promise((c, e) => fs.mkdir(dir, { recursive: true }, err => (err && err.code !== 'EEXIST') ? e(err) : c(dir))); + } + + /** + * @param {string} location + * @returns {Promise} + */ + function rimraf(location) { + return new Promise((c, e) => fs.rmdir(location, { recursive: true }, err => (err && err.code !== 'ENOENT') ? e(err) : c())); + } + + /** + * @param {string} file + * @returns {Promise} + */ + function readFile(file) { + return new Promise((c, e) => fs.readFile(file, 'utf8', (err, data) => err ? e(err) : c(data))); + } + + /** + * @param {string} file + * @param {string} content + * @returns {Promise} + */ + function writeFile(file, content) { + return new Promise((c, e) => fs.writeFile(file, content, 'utf8', err => err ? e(err) : c())); + } + + /** + * @param {string} userDataPath + * @returns {object} + */ + function getLanguagePackConfigurations(userDataPath) { + const configFile = path.join(userDataPath, 'languagepacks.json'); + try { + return nodeRequire(configFile); + } catch (err) { + // Do nothing. If we can't read the file we have no + // language pack config. + } + return undefined; + } + + /** + * @param {object} config + * @param {string} locale + */ + function resolveLanguagePackLocale(config, locale) { + try { + while (locale) { + if (config[locale]) { + return locale; } else { - return undefined; + const index = locale.lastIndexOf('-'); + if (index > 0) { + locale = locale.substring(0, index); + } else { + return undefined; + } } } + } catch (err) { + console.error('Resolving language pack configuration failed.', err); } - } catch (err) { - console.error('Resolving language pack configuration failed.', err); - } - return undefined; - } - - /** - * @param {string} commit - * @param {string} userDataPath - * @param {string} metaDataFile - * @param {string} locale - */ - function getNLSConfiguration(commit, userDataPath, metaDataFile, locale) { - if (locale === 'pseudo') { - return Promise.resolve({ locale: locale, availableLanguages: {}, pseudo: true }); + return undefined; } - if (process.env['VSCODE_DEV']) { - return Promise.resolve({ locale: locale, availableLanguages: {} }); - } - - // We have a built version so we have extracted nls file. Try to find - // the right file to use. - - // Check if we have an English or English US locale. If so fall to default since that is our - // English translation (we don't ship *.nls.en.json files) - if (locale && (locale === 'en' || locale === 'en-us')) { - return Promise.resolve({ locale: locale, availableLanguages: {} }); - } - - const initialLocale = locale; - - perf.mark('code/willGenerateNls'); - - const defaultResult = function (locale) { - perf.mark('code/didGenerateNls'); - return Promise.resolve({ locale: locale, availableLanguages: {} }); - }; - try { - if (!commit) { - return defaultResult(initialLocale); + /** + * @param {string} commit + * @param {string} userDataPath + * @param {string} metaDataFile + * @param {string} locale + */ + function getNLSConfiguration(commit, userDataPath, metaDataFile, locale) { + if (locale === 'pseudo') { + return Promise.resolve({ locale: locale, availableLanguages: {}, pseudo: true }); } - const configs = getLanguagePackConfigurations(userDataPath); - if (!configs) { - return defaultResult(initialLocale); + + if (process.env['VSCODE_DEV']) { + return Promise.resolve({ locale: locale, availableLanguages: {} }); } - locale = resolveLanguagePackLocale(configs, locale); - if (!locale) { - return defaultResult(initialLocale); + + // We have a built version so we have extracted nls file. Try to find + // the right file to use. + + // Check if we have an English or English US locale. If so fall to default since that is our + // English translation (we don't ship *.nls.en.json files) + if (locale && (locale === 'en' || locale === 'en-us')) { + return Promise.resolve({ locale: locale, availableLanguages: {} }); } - const packConfig = configs[locale]; - let mainPack; - if (!packConfig || typeof packConfig.hash !== 'string' || !packConfig.translations || typeof (mainPack = packConfig.translations['vscode']) !== 'string') { - return defaultResult(initialLocale); - } - return exists(mainPack).then(fileExists => { - if (!fileExists) { + + const initialLocale = locale; + + perf.mark('code/willGenerateNls'); + + const defaultResult = function (locale) { + perf.mark('code/didGenerateNls'); + return Promise.resolve({ locale: locale, availableLanguages: {} }); + }; + try { + if (!commit) { return defaultResult(initialLocale); } - const packId = packConfig.hash + '.' + locale; - const cacheRoot = path.join(userDataPath, 'clp', packId); - const coreLocation = path.join(cacheRoot, commit); - const translationsConfigFile = path.join(cacheRoot, 'tcf.json'); - const corruptedFile = path.join(cacheRoot, 'corrupted.info'); - const result = { - locale: initialLocale, - availableLanguages: { '*': locale }, - _languagePackId: packId, - _translationsConfigFile: translationsConfigFile, - _cacheRoot: cacheRoot, - _resolvedLanguagePackCoreLocation: coreLocation, - _corruptedFile: corruptedFile - }; - return exists(corruptedFile).then(corrupted => { - // The nls cache directory is corrupted. - let toDelete; - if (corrupted) { - toDelete = rimraf(cacheRoot); - } else { - toDelete = Promise.resolve(undefined); + const configs = getLanguagePackConfigurations(userDataPath); + if (!configs) { + return defaultResult(initialLocale); + } + locale = resolveLanguagePackLocale(configs, locale); + if (!locale) { + return defaultResult(initialLocale); + } + const packConfig = configs[locale]; + let mainPack; + if (!packConfig || typeof packConfig.hash !== 'string' || !packConfig.translations || typeof (mainPack = packConfig.translations['vscode']) !== 'string') { + return defaultResult(initialLocale); + } + return exists(mainPack).then(fileExists => { + if (!fileExists) { + return defaultResult(initialLocale); } - return toDelete.then(() => { - return exists(coreLocation).then(fileExists => { - if (fileExists) { - // We don't wait for this. No big harm if we can't touch - touch(coreLocation).catch(() => { }); - perf.mark('code/didGenerateNls'); - return result; - } - return mkdirp(coreLocation).then(() => { - return Promise.all([readFile(metaDataFile), readFile(mainPack)]); - }).then(values => { - const metadata = JSON.parse(values[0]); - const packData = JSON.parse(values[1]).contents; - const bundles = Object.keys(metadata.bundles); - const writes = []; - for (const bundle of bundles) { - const modules = metadata.bundles[bundle]; - const target = Object.create(null); - for (const module of modules) { - const keys = metadata.keys[module]; - const defaultMessages = metadata.messages[module]; - const translations = packData[module]; - let targetStrings; - if (translations) { - targetStrings = []; - for (let i = 0; i < keys.length; i++) { - const elem = keys[i]; - const key = typeof elem === 'string' ? elem : elem.key; - let translatedMessage = translations[key]; - if (translatedMessage === undefined) { - translatedMessage = defaultMessages[i]; - } - targetStrings.push(translatedMessage); - } - } else { - targetStrings = defaultMessages; - } - target[module] = targetStrings; - } - writes.push(writeFile(path.join(coreLocation, bundle.replace(/\//g, '!') + '.nls.json'), JSON.stringify(target))); + const packId = packConfig.hash + '.' + locale; + const cacheRoot = path.join(userDataPath, 'clp', packId); + const coreLocation = path.join(cacheRoot, commit); + const translationsConfigFile = path.join(cacheRoot, 'tcf.json'); + const corruptedFile = path.join(cacheRoot, 'corrupted.info'); + const result = { + locale: initialLocale, + availableLanguages: { '*': locale }, + _languagePackId: packId, + _translationsConfigFile: translationsConfigFile, + _cacheRoot: cacheRoot, + _resolvedLanguagePackCoreLocation: coreLocation, + _corruptedFile: corruptedFile + }; + return exists(corruptedFile).then(corrupted => { + // The nls cache directory is corrupted. + let toDelete; + if (corrupted) { + toDelete = rimraf(cacheRoot); + } else { + toDelete = Promise.resolve(undefined); + } + return toDelete.then(() => { + return exists(coreLocation).then(fileExists => { + if (fileExists) { + // We don't wait for this. No big harm if we can't touch + touch(coreLocation).catch(() => { }); + perf.mark('code/didGenerateNls'); + return result; } - writes.push(writeFile(translationsConfigFile, JSON.stringify(packConfig.translations))); - return Promise.all(writes); - }).then(() => { - perf.mark('code/didGenerateNls'); - return result; - }).catch(err => { - console.error('Generating translation files failed.', err); - return defaultResult(locale); + return mkdirp(coreLocation).then(() => { + return Promise.all([readFile(metaDataFile), readFile(mainPack)]); + }).then(values => { + const metadata = JSON.parse(values[0]); + const packData = JSON.parse(values[1]).contents; + const bundles = Object.keys(metadata.bundles); + const writes = []; + for (const bundle of bundles) { + const modules = metadata.bundles[bundle]; + const target = Object.create(null); + for (const module of modules) { + const keys = metadata.keys[module]; + const defaultMessages = metadata.messages[module]; + const translations = packData[module]; + let targetStrings; + if (translations) { + targetStrings = []; + for (let i = 0; i < keys.length; i++) { + const elem = keys[i]; + const key = typeof elem === 'string' ? elem : elem.key; + let translatedMessage = translations[key]; + if (translatedMessage === undefined) { + translatedMessage = defaultMessages[i]; + } + targetStrings.push(translatedMessage); + } + } else { + targetStrings = defaultMessages; + } + target[module] = targetStrings; + } + writes.push(writeFile(path.join(coreLocation, bundle.replace(/\//g, '!') + '.nls.json'), JSON.stringify(target))); + } + writes.push(writeFile(translationsConfigFile, JSON.stringify(packConfig.translations))); + return Promise.all(writes); + }).then(() => { + perf.mark('code/didGenerateNls'); + return result; + }).catch(err => { + console.error('Generating translation files failed.', err); + return defaultResult(locale); + }); }); }); }); }); - }); - } catch (err) { - console.error('Generating translation files failed.', err); - return defaultResult(locale); + } catch (err) { + console.error('Generating translation files failed.', err); + return defaultResult(locale); + } } + + return { + getNLSConfiguration + }; } - return { - getNLSConfiguration - }; -} - - -// @ts-ignore -if (typeof define === 'function') { - // amd - // @ts-ignore - define(['path', 'fs', 'vs/base/common/performance'], function (path, fs, perf) { return factory(require.__$__nodeRequire, path, fs, perf); }); -} else if (typeof module === 'object' && typeof module.exports === 'object') { - const path = require('path'); - const fs = require('fs'); - const perf = require('../common/performance'); - module.exports = factory(require, path, fs, perf); -} else { - throw new Error('Unknown context'); -} + if (typeof define === 'function') { + // amd + define(['require', 'path', 'fs', 'vs/base/common/performance'], function (require, /** @type {typeof import('path')} */ path, /** @type {typeof import('fs')} */ fs, /** @type {typeof import('../common/performance')} */ perf) { return factory(require.__$__nodeRequire, path, fs, perf); }); + } else if (typeof module === 'object' && typeof module.exports === 'object') { + const path = require('path'); + const fs = require('fs'); + const perf = require('../common/performance'); + module.exports = factory(require, path, fs, perf); + } else { + throw new Error('Unknown context'); + } +}()); diff --git a/src/vs/base/node/userDataPath.d.ts b/src/vs/base/node/userDataPath.d.ts new file mode 100644 index 00000000000..bc09b834a7e --- /dev/null +++ b/src/vs/base/node/userDataPath.d.ts @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/** + * Returns the user data path to use. + */ +export function getDefaultUserDataPath(): string; diff --git a/src/vs/base/node/userDataPath.js b/src/vs/base/node/userDataPath.js new file mode 100644 index 00000000000..93384cb8f4e --- /dev/null +++ b/src/vs/base/node/userDataPath.js @@ -0,0 +1,72 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/// + +//@ts-check +(function () { + 'use strict'; + + /** + * @param {typeof import('path')} path + * @param {typeof import('os')} os + * @param {string} productName + */ + function factory(path, os, productName) { + + function getDefaultUserDataPath() { + + // Support global VSCODE_APPDATA environment variable + let appDataPath = process.env['VSCODE_APPDATA']; + + // Otherwise check per platform + if (!appDataPath) { + switch (process.platform) { + case 'win32': + appDataPath = process.env['APPDATA']; + if (!appDataPath) { + const userProfile = process.env['USERPROFILE']; + if (typeof userProfile !== 'string') { + throw new Error('Windows: Unexpected undefined %USERPROFILE% environment variable'); + } + appDataPath = path.join(userProfile, 'AppData', 'Roaming'); + } + break; + case 'darwin': + appDataPath = path.join(os.homedir(), 'Library', 'Application Support'); + break; + case 'linux': + appDataPath = process.env['XDG_CONFIG_HOME'] || path.join(os.homedir(), '.config'); + break; + default: + throw new Error('Platform not supported'); + } + } + + return path.join(appDataPath, productName); + } + + return { + getDefaultUserDataPath + }; + } + + if (typeof define === 'function') { + define(['require', 'path', 'os', 'vs/base/common/network', 'vs/base/common/resources'], function (require, /** @type {typeof import('path')} */ path, /** @type {typeof import('os')} */ os, /** @type {typeof import('../common/network')} */ network, /** @type {typeof import("../common/resources")} */ resources) { + const rootPath = resources.dirname(network.FileAccess.asFileUri('', require)); + const pkg = require.__$__nodeRequire(resources.joinPath(rootPath, 'package.json').fsPath); + + return factory(path, os, pkg.name); + }); // amd + } else if (typeof module === 'object' && typeof module.exports === 'object') { + const pkg = require('../../../../package.json'); + const path = require('path'); + const os = require('os'); + + module.exports = factory(path, os, pkg.name); // commonjs + } else { + throw new Error('Unknown context'); + } +}()); diff --git a/src/vs/base/node/paths.ts b/src/vs/base/test/node/userDataPath.test.ts similarity index 56% rename from src/vs/base/node/paths.ts rename to src/vs/base/test/node/userDataPath.test.ts index eaf03e6e400..74d0ae4f26e 100644 --- a/src/vs/base/node/paths.ts +++ b/src/vs/base/test/node/userDataPath.test.ts @@ -3,9 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { FileAccess } from 'vs/base/common/network'; +import * as assert from 'assert'; +import { getDefaultUserDataPath } from 'vs/base/node/userDataPath'; -const pathsPath = FileAccess.asFileUri('paths', require).fsPath; -const paths = require.__$__nodeRequire<{ getDefaultUserDataPath(): string }>(pathsPath); +suite('User data path', () => { -export const getDefaultUserDataPath = paths.getDefaultUserDataPath; + test('getDefaultUserDataPath', () => { + const path = getDefaultUserDataPath(); + assert.ok(path.length > 0); + }); +}); diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcess.js b/src/vs/code/electron-browser/sharedProcess/sharedProcess.js index 2bb0a0bb730..50d8d3f7f8f 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcess.js +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcess.js @@ -4,9 +4,9 @@ *--------------------------------------------------------------------------------------------*/ //@ts-check -'use strict'; - (function () { + 'use strict'; + const bootstrap = bootstrapLib(); const bootstrapWindow = bootstrapWindowLib(); @@ -38,5 +38,4 @@ } //#endregion - }()); diff --git a/src/vs/code/electron-browser/workbench/workbench.js b/src/vs/code/electron-browser/workbench/workbench.js index 64082146a6d..0c52f3cda25 100644 --- a/src/vs/code/electron-browser/workbench/workbench.js +++ b/src/vs/code/electron-browser/workbench/workbench.js @@ -6,9 +6,9 @@ /// //@ts-check -'use strict'; - (function () { + 'use strict'; + const bootstrapWindow = bootstrapWindowLib(); // Add a perf entry right from the top @@ -179,5 +179,4 @@ } //#endregion - }()); diff --git a/src/vs/code/electron-sandbox/issue/issueReporter.js b/src/vs/code/electron-sandbox/issue/issueReporter.js index 2c3529754b3..a51159e580e 100644 --- a/src/vs/code/electron-sandbox/issue/issueReporter.js +++ b/src/vs/code/electron-sandbox/issue/issueReporter.js @@ -4,9 +4,9 @@ *--------------------------------------------------------------------------------------------*/ //@ts-check -'use strict'; - (function () { + 'use strict'; + const bootstrapWindow = bootstrapWindowLib(); // Load issue reporter into window diff --git a/src/vs/code/electron-sandbox/processExplorer/processExplorer.js b/src/vs/code/electron-sandbox/processExplorer/processExplorer.js index 3b84f3acf06..36fb6ee5530 100644 --- a/src/vs/code/electron-sandbox/processExplorer/processExplorer.js +++ b/src/vs/code/electron-sandbox/processExplorer/processExplorer.js @@ -4,9 +4,9 @@ *--------------------------------------------------------------------------------------------*/ //@ts-check -'use strict'; - (function () { + 'use strict'; + const bootstrapWindow = bootstrapWindowLib(); // Load process explorer into window diff --git a/src/vs/code/electron-sandbox/workbench/workbench.js b/src/vs/code/electron-sandbox/workbench/workbench.js index c5cb1debb26..06edaee9432 100644 --- a/src/vs/code/electron-sandbox/workbench/workbench.js +++ b/src/vs/code/electron-sandbox/workbench/workbench.js @@ -5,10 +5,10 @@ /// -//@ts-check -'use strict'; - +// @ts-check (function () { + 'use strict'; + const bootstrapWindow = bootstrapWindowLib(); // Add a perf entry right from the top diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index f5c79cc4f0d..b9bf96a83e4 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -3,14 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as os from 'os'; +import { homedir, tmpdir } from 'os'; +import product from 'vs/platform/product/common/product'; import { IDebugParams, IExtensionHostDebugParams, INativeEnvironmentService } from 'vs/platform/environment/common/environment'; import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; -import * as paths from 'vs/base/node/paths'; -import * as path from 'vs/base/common/path'; -import * as resources from 'vs/base/common/resources'; +import { getDefaultUserDataPath } from 'vs/base/node/userDataPath'; +import { dirname, join, normalize, resolve } from 'vs/base/common/path'; +import { joinPath } from 'vs/base/common/resources'; import { memoize } from 'vs/base/common/decorators'; -import product from 'vs/platform/product/common/product'; import { toLocalISOString } from 'vs/base/common/date'; import { FileAccess } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; @@ -22,46 +22,46 @@ export class NativeEnvironmentService implements INativeEnvironmentService { get args(): NativeParsedArgs { return this._args; } @memoize - get appRoot(): string { return path.dirname(FileAccess.asFileUri('', require).fsPath); } + get appRoot(): string { return dirname(FileAccess.asFileUri('', require).fsPath); } readonly logsPath: string; @memoize - get userHome(): URI { return URI.file(os.homedir()); } + get userHome(): URI { return URI.file(homedir()); } @memoize get userDataPath(): string { const vscodePortable = process.env['VSCODE_PORTABLE']; if (vscodePortable) { - return path.join(vscodePortable, 'user-data'); + return join(vscodePortable, 'user-data'); } return parseUserDataDir(this._args, process); } @memoize - get appSettingsHome(): URI { return URI.file(path.join(this.userDataPath, 'User')); } + get appSettingsHome(): URI { return URI.file(join(this.userDataPath, 'User')); } @memoize - get tmpDir(): URI { return URI.file(os.tmpdir()); } + get tmpDir(): URI { return URI.file(tmpdir()); } @memoize get userRoamingDataHome(): URI { return this.appSettingsHome; } @memoize - get settingsResource(): URI { return resources.joinPath(this.userRoamingDataHome, 'settings.json'); } + get settingsResource(): URI { return joinPath(this.userRoamingDataHome, 'settings.json'); } @memoize - get userDataSyncHome(): URI { return resources.joinPath(this.userRoamingDataHome, 'sync'); } + get userDataSyncHome(): URI { return joinPath(this.userRoamingDataHome, 'sync'); } @memoize - get userDataSyncLogResource(): URI { return URI.file(path.join(this.logsPath, 'userDataSync.log')); } + get userDataSyncLogResource(): URI { return URI.file(join(this.logsPath, 'userDataSync.log')); } @memoize get sync(): 'on' | 'off' | undefined { return this.args.sync; } @memoize - get machineSettingsResource(): URI { return resources.joinPath(URI.file(path.join(this.userDataPath, 'Machine')), 'settings.json'); } + get machineSettingsResource(): URI { return joinPath(URI.file(join(this.userDataPath, 'Machine')), 'settings.json'); } @memoize get globalStorageHome(): URI { return URI.joinPath(this.appSettingsHome, 'globalStorage'); } @@ -70,32 +70,32 @@ export class NativeEnvironmentService implements INativeEnvironmentService { get workspaceStorageHome(): URI { return URI.joinPath(this.appSettingsHome, 'workspaceStorage'); } @memoize - get keybindingsResource(): URI { return resources.joinPath(this.userRoamingDataHome, 'keybindings.json'); } + get keybindingsResource(): URI { return joinPath(this.userRoamingDataHome, 'keybindings.json'); } @memoize - get keyboardLayoutResource(): URI { return resources.joinPath(this.userRoamingDataHome, 'keyboardLayout.json'); } + get keyboardLayoutResource(): URI { return joinPath(this.userRoamingDataHome, 'keyboardLayout.json'); } @memoize get argvResource(): URI { const vscodePortable = process.env['VSCODE_PORTABLE']; if (vscodePortable) { - return URI.file(path.join(vscodePortable, 'argv.json')); + return URI.file(join(vscodePortable, 'argv.json')); } - return resources.joinPath(this.userHome, product.dataFolderName, 'argv.json'); + return joinPath(this.userHome, product.dataFolderName, 'argv.json'); } @memoize - get snippetsHome(): URI { return resources.joinPath(this.userRoamingDataHome, 'snippets'); } + get snippetsHome(): URI { return joinPath(this.userRoamingDataHome, 'snippets'); } @memoize get isExtensionDevelopment(): boolean { return !!this._args.extensionDevelopmentPath; } @memoize - get untitledWorkspacesHome(): URI { return URI.file(path.join(this.userDataPath, 'Workspaces')); } + get untitledWorkspacesHome(): URI { return URI.file(join(this.userDataPath, 'Workspaces')); } @memoize - get installSourcePath(): string { return path.join(this.userDataPath, 'installSource'); } + get installSourcePath(): string { return join(this.userDataPath, 'installSource'); } @memoize get builtinExtensionsPath(): string { @@ -103,7 +103,7 @@ export class NativeEnvironmentService implements INativeEnvironmentService { if (fromArgs) { return fromArgs; } else { - return path.normalize(path.join(FileAccess.asFileUri('', require).fsPath, '..', 'extensions')); + return normalize(join(FileAccess.asFileUri('', require).fsPath, '..', 'extensions')); } } @@ -112,7 +112,7 @@ export class NativeEnvironmentService implements INativeEnvironmentService { if (fromArgs) { return fromArgs; } else { - return path.join(this.userDataPath, 'CachedExtensionVSIXs'); + return join(this.userDataPath, 'CachedExtensionVSIXs'); } } @@ -131,10 +131,10 @@ export class NativeEnvironmentService implements INativeEnvironmentService { const vscodePortable = process.env['VSCODE_PORTABLE']; if (vscodePortable) { - return path.join(vscodePortable, 'extensions'); + return join(vscodePortable, 'extensions'); } - return resources.joinPath(this.userHome, product.dataFolderName, 'extensions').fsPath; + return joinPath(this.userHome, product.dataFolderName, 'extensions').fsPath; } @memoize @@ -145,7 +145,7 @@ export class NativeEnvironmentService implements INativeEnvironmentService { if (/^[^:/?#]+?:\/\//.test(p)) { return URI.parse(p); } - return URI.file(path.normalize(p)); + return URI.file(normalize(p)); }); } return undefined; @@ -158,7 +158,7 @@ export class NativeEnvironmentService implements INativeEnvironmentService { if (/^[^:/?#]+?:\/\//.test(s)) { return URI.parse(s); } - return URI.file(path.normalize(s)); + return URI.file(normalize(s)); } return undefined; } @@ -188,7 +188,7 @@ export class NativeEnvironmentService implements INativeEnvironmentService { get logLevel(): string | undefined { return this._args.log; } @memoize - get serviceMachineIdResource(): URI { return resources.joinPath(URI.file(this.userDataPath), 'machineid'); } + get serviceMachineIdResource(): URI { return joinPath(URI.file(this.userDataPath), 'machineid'); } get crashReporterId(): string | undefined { return this._args['crash-reporter-id']; } get crashReporterDirectory(): string | undefined { return this._args['crash-reporter-directory']; } @@ -196,13 +196,13 @@ export class NativeEnvironmentService implements INativeEnvironmentService { get driverHandle(): string | undefined { return this._args['driver']; } @memoize - get telemetryLogResource(): URI { return URI.file(path.join(this.logsPath, 'telemetry.log')); } + get telemetryLogResource(): URI { return URI.file(join(this.logsPath, 'telemetry.log')); } get disableTelemetry(): boolean { return !!this._args['disable-telemetry']; } constructor(protected _args: NativeParsedArgs) { if (!_args.logsPath) { const key = toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, ''); - _args.logsPath = path.join(this.userDataPath, 'logs', key); + _args.logsPath = join(this.userDataPath, 'logs', key); } this.logsPath = _args.logsPath; } @@ -231,15 +231,15 @@ export function parsePathArg(arg: string | undefined, process: NodeJS.Process): // Determine if the arg is relative or absolute, if relative use the original CWD // (VSCODE_CWD), not the potentially overridden one (process.cwd()). - const resolved = path.resolve(arg); + const resolved = resolve(arg); - if (path.normalize(arg) === resolved) { + if (normalize(arg) === resolved) { return resolved; } - return path.resolve(process.env['VSCODE_CWD'] || process.cwd(), arg); + return resolve(process.env['VSCODE_CWD'] || process.cwd(), arg); } export function parseUserDataDir(args: NativeParsedArgs, process: NodeJS.Process): string { - return parsePathArg(args['user-data-dir'], process) || path.resolve(paths.getDefaultUserDataPath()); + return parsePathArg(args['user-data-dir'], process) || resolve(getDefaultUserDataPath()); } diff --git a/src/vs/platform/product/common/productService.ts b/src/vs/platform/product/common/productService.ts index 92b8c1a6d52..3f6ace923a6 100644 --- a/src/vs/platform/product/common/productService.ts +++ b/src/vs/platform/product/common/productService.ts @@ -45,7 +45,7 @@ export interface IProductConfiguration { readonly applicationName: string; readonly urlProtocol: string; - readonly dataFolderName: string; + readonly dataFolderName: string; // location for extensions (e.g. ~/.vscode-insiders) readonly builtInExtensions?: IBuiltInExtension[]; From 815694184dd38f4b02747c9ee311509febbb30ff Mon Sep 17 00:00:00 2001 From: Kelvin Schoofs Date: Fri, 12 Feb 2021 16:18:47 +0100 Subject: [PATCH 069/325] Unrecognized variables with arguments getting truncated (#114474) This PR fixes #114473 --- .../services/configurationResolver/common/variableResolver.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/services/configurationResolver/common/variableResolver.ts b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts index 2d39c5bcd34..507dd8595b9 100644 --- a/src/vs/workbench/services/configurationResolver/common/variableResolver.ts +++ b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts @@ -326,7 +326,8 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe default: try { - return this.resolveFromMap(match, variable, commandValueMapping, undefined); + const key = argument ? `${variable}:${argument}` : variable; + return this.resolveFromMap(match, key, commandValueMapping, undefined); } catch (error) { return match; } From dc4fa4878fb75c920046d54f1d96c9b6a6b3c2c6 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 08:23:43 -0800 Subject: [PATCH 070/325] Bring ptyService into shared proc Hopefully to get tests passing --- package.json | 2 +- remote/package.json | 2 +- remote/web/package.json | 2 +- remote/web/yarn.lock | 8 +- remote/yarn.lock | 8 +- scripts/test-integration.sh | 10 +-- .../electron-browser/localPtyService.ts | 90 ++++++++++--------- yarn.lock | 8 +- 8 files changed, 63 insertions(+), 67 deletions(-) diff --git a/package.json b/package.json index c6300383bea..b081a2aa694 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "native-is-elevated": "0.4.1", "native-keymap": "2.2.1", "native-watchdog": "1.3.0", - "node-pty": "0.11.0-beta1", + "node-pty": "0.10.0-beta19", "spdlog": "^0.11.1", "sudo-prompt": "9.1.1", "tas-client-umd": "0.1.2", diff --git a/remote/package.json b/remote/package.json index 86a8a64cb84..3d36902888e 100644 --- a/remote/package.json +++ b/remote/package.json @@ -13,7 +13,7 @@ "jschardet": "2.2.1", "minimist": "^1.2.5", "native-watchdog": "1.3.0", - "node-pty": "0.11.0-beta1", + "node-pty": "0.10.0-beta19", "spdlog": "^0.11.1", "tas-client-umd": "0.1.2", "vscode-nsfw": "1.2.9", diff --git a/remote/web/package.json b/remote/web/package.json index 040d0a926fe..577b0cbbb8d 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -5,7 +5,7 @@ "dependencies": { "iconv-lite-umd": "0.6.8", "jschardet": "2.2.1", - "node-pty": "0.11.0-beta1", + "node-pty": "0.10.0-beta19", "tas-client-umd": "0.1.2", "vscode-oniguruma": "1.3.1", "vscode-textmate": "5.2.0", diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 21482b82927..f69cbd4d1fc 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -17,10 +17,10 @@ nan@^2.14.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== -node-pty@0.11.0-beta1: - version "0.11.0-beta1" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.11.0-beta1.tgz#961cf7ab56e0a689b71a19a46371ea090050f312" - integrity sha512-nHMB0K3LZTqjWv3X11XFdy/L4V2eMEk0RbmbVN02GPOkXdMy2NITI0px/x0JtNeIolRPq6r5hf5NUcNc2LJizw== +node-pty@0.10.0-beta19: + version "0.10.0-beta19" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.0-beta19.tgz#b7cbfba53f7b2a816efe8c9302dd083cc5874458" + integrity sha512-4UIOGMvpofUbe+ZniBUtY8zc/psMURSzbMonQgIhK7JlMQsUwcbkDIrKzStVLJX0FkeZpUNlsVtK7qqzHvrUZA== dependencies: nan "^2.14.0" diff --git a/remote/yarn.lock b/remote/yarn.lock index 35efe72cbb4..a264b79dde8 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -304,10 +304,10 @@ node-addon-api@^3.0.2: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.0.2.tgz#04bc7b83fd845ba785bb6eae25bc857e1ef75681" integrity sha512-+D4s2HCnxPd5PjjI0STKwncjXTUKKqm74MDMz9OPXavjsGmjkvwgLtA5yoxJUdmpj52+2u+RrXgPipahKczMKg== -node-pty@0.11.0-beta1: - version "0.11.0-beta1" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.11.0-beta1.tgz#961cf7ab56e0a689b71a19a46371ea090050f312" - integrity sha512-nHMB0K3LZTqjWv3X11XFdy/L4V2eMEk0RbmbVN02GPOkXdMy2NITI0px/x0JtNeIolRPq6r5hf5NUcNc2LJizw== +node-pty@0.10.0-beta19: + version "0.10.0-beta19" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.0-beta19.tgz#b7cbfba53f7b2a816efe8c9302dd083cc5874458" + integrity sha512-4UIOGMvpofUbe+ZniBUtY8zc/psMURSzbMonQgIhK7JlMQsUwcbkDIrKzStVLJX0FkeZpUNlsVtK7qqzHvrUZA== dependencies: nan "^2.14.0" diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index 610759621b6..b1d5e9588e3 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -55,15 +55,9 @@ else fi if [ -z "$INTEGRATION_TEST_APP_NAME" ]; then - after_suite() { - true; - ps -aef --forest; - } + after_suite() { true; } else - after_suite() { - killall $INTEGRATION_TEST_APP_NAME || true; - ps -aef --forest; - } + after_suite() { killall $INTEGRATION_TEST_APP_NAME || true; } fi # Integration tests in AMD diff --git a/src/vs/platform/terminal/electron-browser/localPtyService.ts b/src/vs/platform/terminal/electron-browser/localPtyService.ts index e39be645dc7..d4c19fc86ef 100644 --- a/src/vs/platform/terminal/electron-browser/localPtyService.ts +++ b/src/vs/platform/terminal/electron-browser/localPtyService.ts @@ -5,13 +5,14 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { ILogService } from 'vs/platform/log/common/log'; -import { IPtyService, IProcessDataEvent, IShellLaunchConfig, ITerminalDimensionsOverride, ITerminalLaunchError, TerminalIpcChannels } from 'vs/platform/terminal/common/terminal'; -import { Client } from 'vs/base/parts/ipc/node/ipc.cp'; -import { FileAccess } from 'vs/base/common/network'; -import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc'; +import { IPtyService, IProcessDataEvent, IShellLaunchConfig, ITerminalDimensionsOverride, ITerminalLaunchError } from 'vs/platform/terminal/common/terminal'; +// import { Client } from 'vs/base/parts/ipc/node/ipc.cp'; +// import { FileAccess } from 'vs/base/common/network'; +// import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc'; import { IProcessEnvironment } from 'vs/base/common/platform'; import { Emitter } from 'vs/base/common/event'; -import { LogLevelChannelClient } from 'vs/platform/log/common/logIpc'; +// import { LogLevelChannelClient } from 'vs/platform/log/common/logIpc'; +import { PtyService } from 'vs/platform/terminal/node/ptyService'; // enum Constants { // MaxRestarts = 5 @@ -53,50 +54,51 @@ export class LocalPtyService extends Disposable implements IPtyService { } private _startPtyHost(): IPtyService { - const client = this._register(new Client( - FileAccess.asFileUri('bootstrap-fork', require).fsPath, - { - serverName: 'Pty Host', - args: ['--type=ptyHost'], - env: { - VSCODE_AMD_ENTRYPOINT: 'vs/platform/terminal/node/ptyHostMain', - VSCODE_PIPE_LOGGING: 'true', - VSCODE_VERBOSE_LOGGING: 'true' // transmit console logs from server to client - } - } - )); - this._onPtyHostStart.fire(); + // const client = this._register(new Client( + // FileAccess.asFileUri('bootstrap-fork', require).fsPath, + // { + // serverName: 'Pty Host', + // args: ['--type=ptyHost'], + // env: { + // VSCODE_AMD_ENTRYPOINT: 'vs/platform/terminal/node/ptyHostMain', + // VSCODE_PIPE_LOGGING: 'true', + // VSCODE_VERBOSE_LOGGING: 'true' // transmit console logs from server to client + // } + // } + // )); + // this._onPtyHostStart.fire(); - // Handle exit - this._register({ - dispose: () => { - if (proxy.shutdownAll) { - proxy.shutdownAll(); - } - client.dispose(); - } - }); - this._register(client.onDidProcessExit(e => { - this._onPtyHostExit.fire(e.code); - // if (!this._isDisposed) { - // if (this._restartCount <= Constants.MaxRestarts) { - // this._logService.error(`ptyHost terminated unexpectedly with code ${e.code}`); - // this._restartCount++; - // this._proxy = this._startPtyHost(); - // } else { - // this._logService.error(`ptyHost terminated unexpectedly with code ${e.code}, giving up`); - // } - // } - })); + // // Handle exit + // this._register({ + // dispose: () => { + // if (proxy.shutdownAll) { + // proxy.shutdownAll(); + // } + // client.dispose(); + // } + // }); + // this._register(client.onDidProcessExit(e => { + // this._onPtyHostExit.fire(e.code); + // // if (!this._isDisposed) { + // // if (this._restartCount <= Constants.MaxRestarts) { + // // this._logService.error(`ptyHost terminated unexpectedly with code ${e.code}`); + // // this._restartCount++; + // // this._proxy = this._startPtyHost(); + // // } else { + // // this._logService.error(`ptyHost terminated unexpectedly with code ${e.code}, giving up`); + // // } + // // } + // })); // Setup logging - const logChannel = client.getChannel(TerminalIpcChannels.Log); - this._register(this._logService.onDidChangeLogLevel(() => { - LogLevelChannelClient.setLevel(logChannel, this._logService.getLevel()); - })); + // const logChannel = client.getChannel(TerminalIpcChannels.Log); + // this._register(this._logService.onDidChangeLogLevel(() => { + // LogLevelChannelClient.setLevel(logChannel, this._logService.getLevel()); + // })); // Create proxy and forward events - const proxy = ProxyChannel.toService(client.getChannel(TerminalIpcChannels.PtyHost)); + const proxy = new PtyService(this._logService); + // const proxy = ProxyChannel.toService(client.getChannel(TerminalIpcChannels.PtyHost)); this._register(proxy.onProcessData(e => this._onProcessData.fire(e))); this._register(proxy.onProcessExit(e => this._onProcessExit.fire(e))); this._register(proxy.onProcessReady(e => this._onProcessReady.fire(e))); diff --git a/yarn.lock b/yarn.lock index f1705f10ebd..8695942fcec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6672,10 +6672,10 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" -node-pty@0.11.0-beta1: - version "0.11.0-beta1" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.11.0-beta1.tgz#961cf7ab56e0a689b71a19a46371ea090050f312" - integrity sha512-nHMB0K3LZTqjWv3X11XFdy/L4V2eMEk0RbmbVN02GPOkXdMy2NITI0px/x0JtNeIolRPq6r5hf5NUcNc2LJizw== +node-pty@0.10.0-beta19: + version "0.10.0-beta19" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.0-beta19.tgz#b7cbfba53f7b2a816efe8c9302dd083cc5874458" + integrity sha512-4UIOGMvpofUbe+ZniBUtY8zc/psMURSzbMonQgIhK7JlMQsUwcbkDIrKzStVLJX0FkeZpUNlsVtK7qqzHvrUZA== dependencies: nan "^2.14.0" From 4713b130e11303cc1c75934cfaaebc69baaebe89 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 09:00:09 -0800 Subject: [PATCH 071/325] Register ptyservice in localptyservice --- src/vs/platform/terminal/electron-browser/localPtyService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/terminal/electron-browser/localPtyService.ts b/src/vs/platform/terminal/electron-browser/localPtyService.ts index d4c19fc86ef..4944517f2d9 100644 --- a/src/vs/platform/terminal/electron-browser/localPtyService.ts +++ b/src/vs/platform/terminal/electron-browser/localPtyService.ts @@ -97,7 +97,7 @@ export class LocalPtyService extends Disposable implements IPtyService { // })); // Create proxy and forward events - const proxy = new PtyService(this._logService); + const proxy = this._register(new PtyService(this._logService)); // const proxy = ProxyChannel.toService(client.getChannel(TerminalIpcChannels.PtyHost)); this._register(proxy.onProcessData(e => this._onProcessData.fire(e))); this._register(proxy.onProcessExit(e => this._onProcessExit.fire(e))); From ac1ba3312740d5327fecebcecd09280961031ba5 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 12 Feb 2021 09:03:02 -0800 Subject: [PATCH 072/325] testing: add tests for and fix bugs in test result service --- .../testing/common/testResultService.ts | 45 +++-- .../contrib/testing/common/testServiceImpl.ts | 2 +- .../test/common/ownedTestCollection.ts | 14 ++ .../test/common/testResultService.test.ts | 187 ++++++++++++++++++ 4 files changed, 231 insertions(+), 17 deletions(-) create mode 100644 src/vs/workbench/contrib/testing/test/common/testResultService.test.ts diff --git a/src/vs/workbench/contrib/testing/common/testResultService.ts b/src/vs/workbench/contrib/testing/common/testResultService.ts index bc2cbda0ca8..a0262052764 100644 --- a/src/vs/workbench/contrib/testing/common/testResultService.ts +++ b/src/vs/workbench/contrib/testing/common/testResultService.ts @@ -50,7 +50,7 @@ export interface ITestResult { toJSON(): ISerializedResults; } -const makeEmptyCounts = () => { +export const makeEmptyCounts = () => { const o: Partial = {}; for (const state of statesInOrder) { o[state] = 0; @@ -148,11 +148,10 @@ const makeNodeAndChildren = ( interface ISerializedResults { id: string; - counts: TestStateCount; - items: Iterable<[extId: string, item: TestResultItem]>; + items: (Omit & { children: string[], retired: undefined })[]; } -interface TestResultItem extends IncrementalTestCollectionItem { +export interface TestResultItem extends IncrementalTestCollectionItem { state: ITestState; computedState: TestRunState; retired: boolean; @@ -273,7 +272,7 @@ export class LiveTestResult implements ITestResult { public setAllToState(state: ITestState, when: (_t: TestResultItem) => boolean) { for (const test of this.testByInternalId.values()) { if (when(test)) { - this.counts[state.state]--; + this.counts[test.state.state]--; test.state = state; this.counts[state.state]++; refreshComputedState(this.computedStateAccessor, test, t => this.changeEmitter.fire(t)); @@ -336,7 +335,11 @@ export class LiveTestResult implements ITestResult { for (const collection of this.collections) { let test = collection.getNodeById(testId); if (test) { - return makeNodeAndChildren(collection, test, this.testByExtId, this.testByInternalId); + const originalSize = this.testByExtId.size; + makeParents(collection, test, this.testByExtId, this.testByInternalId); + const node = makeNodeAndChildren(collection, test, this.testByExtId, this.testByInternalId); + this.counts[TestRunState.Unset] += this.testByExtId.size - originalSize; + return node; } } @@ -361,7 +364,14 @@ export class LiveTestResult implements ITestResult { * @inheritdoc */ public toJSON(): ISerializedResults { - return { id: this.id, counts: this.counts, items: [...this.testByExtId.entries()] }; + return { + id: this.id, + items: [...this.testByExtId.values()].map(entry => ({ + ...entry, + retired: undefined, + children: [...entry.children], + })), + }; } } @@ -372,30 +382,33 @@ class HydratedTestResult implements ITestResult { /** * @inheritdoc */ - public readonly counts = this.serialized.counts; + public readonly counts = makeEmptyCounts(); /** * @inheritdoc */ - public readonly id = this.serialized.id; + public readonly id: string; /** * @inheritdoc */ public readonly isComplete = true; - private readonly map = new Map(); + private readonly byExtId = new Map(); constructor(private readonly serialized: ISerializedResults) { - for (const [key, value] of serialized.items) { - this.map.set(key, value); + this.id = serialized.id; - value.retired = true; - for (const message of value.state.messages) { + for (const item of serialized.items) { + const cast: TestResultItem = { ...item, retired: true, children: new Set(item.children) }; + for (const message of cast.state.messages) { if (message.location) { message.location.uri = URI.revive(message.location.uri); } } + + this.counts[item.state.state]++; + this.byExtId.set(item.item.extId, cast); } } @@ -403,7 +416,7 @@ class HydratedTestResult implements ITestResult { * @inheritdoc */ public getStateByExtId(extTestId: string) { - return this.map.get(extTestId); + return this.byExtId.get(extTestId); } /** @@ -568,7 +581,7 @@ export class TestResultService implements ITestResultService { private onComplete(result: LiveTestResult) { // move the complete test run down behind any still-running ones - for (let i = 0; i < this.results.length - 2; i++) { + for (let i = 0; i < this.results.length - 1; i++) { if (this.results[i].isComplete && !this.results[i + 1].isComplete) { [this.results[i], this.results[i + 1]] = [this.results[i + 1], this.results[i]]; } diff --git a/src/vs/workbench/contrib/testing/common/testServiceImpl.ts b/src/vs/workbench/contrib/testing/common/testServiceImpl.ts index 8a18a20daa5..58787aa18f2 100644 --- a/src/vs/workbench/contrib/testing/common/testServiceImpl.ts +++ b/src/vs/workbench/contrib/testing/common/testServiceImpl.ts @@ -242,7 +242,7 @@ export class TestService extends Disposable implements ITestService { } } -class MainThreadTestCollection extends AbstractIncrementalTestCollection implements IMainThreadTestCollection { +export class MainThreadTestCollection extends AbstractIncrementalTestCollection implements IMainThreadTestCollection { private pendingRootChangeEmitter = new Emitter(); private busyProvidersChangeEmitter = new Emitter(); private _busyProviders = 0; diff --git a/src/vs/workbench/contrib/testing/test/common/ownedTestCollection.ts b/src/vs/workbench/contrib/testing/test/common/ownedTestCollection.ts index a0f841e4b3e..8df8bb684ff 100644 --- a/src/vs/workbench/contrib/testing/test/common/ownedTestCollection.ts +++ b/src/vs/workbench/contrib/testing/test/common/ownedTestCollection.ts @@ -5,6 +5,8 @@ import { OwnedTestCollection, SingleUseTestCollection } from 'vs/workbench/contrib/testing/common/ownedTestCollection'; import { TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection'; +import { MainThreadTestCollection } from 'vs/workbench/contrib/testing/common/testServiceImpl'; +import { testStubs } from 'vs/workbench/contrib/testing/common/testStubs'; export class TestSingleUseCollection extends SingleUseTestCollection { private idCounter = 0; @@ -35,3 +37,15 @@ export class TestOwnedTestCollection extends OwnedTestCollection { return new TestSingleUseCollection(this.testIdToInternal, publishDiff); } } + +/** + * Gets a main thread test collection initialized with the given set of + * roots/stubs. + */ +export const getInitializedMainTestCollection = (root = testStubs.nested()) => { + const c = new MainThreadTestCollection(0); + const singleUse = new TestSingleUseCollection(new Map(), () => undefined); + singleUse.addRoot(root, 'provider'); + c.apply(singleUse.collectDiff()); + return c; +}; diff --git a/src/vs/workbench/contrib/testing/test/common/testResultService.test.ts b/src/vs/workbench/contrib/testing/test/common/testResultService.test.ts new file mode 100644 index 00000000000..c18dab77484 --- /dev/null +++ b/src/vs/workbench/contrib/testing/test/common/testResultService.test.ts @@ -0,0 +1,187 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; +import { InternalTestItem } from 'vs/workbench/contrib/testing/common/testCollection'; +import { LiveTestResult, makeEmptyCounts, TestResultItem, TestResultService } from 'vs/workbench/contrib/testing/common/testResultService'; +import { ReExportedTestRunState as TestRunState } from 'vs/workbench/contrib/testing/common/testStubs'; +import { getInitializedMainTestCollection } from 'vs/workbench/contrib/testing/test/common/ownedTestCollection'; +import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices'; + +suite('Workbench - Test Results Service', () => { + const getLabelsIn = (it: Iterable) => [...it].map(t => t.item.label).sort(); + + let r: LiveTestResult; + let changed = new Set(); + let retired = new Set(); + + setup(() => { + changed = new Set(); + retired = new Set(); + r = LiveTestResult.from( + [getInitializedMainTestCollection()], + [{ providerId: 'provider', testId: '1' }] + ); + + r.onChange(e => changed.add(e)); + r.onRetired(e => retired.add(e)); + }); + + suite('LiveTestResult', () => { + test('is empty if no tests are requesteed', () => { + const r = LiveTestResult.from([getInitializedMainTestCollection()], []); + assert.deepStrictEqual(getLabelsIn(r.tests), []); + }); + + test('does not change or retire initially', () => { + assert.deepStrictEqual(0, changed.size); + assert.deepStrictEqual(0, retired.size); + }); + + test('initializes with the subtree of requested tests', () => { + assert.deepStrictEqual(getLabelsIn(r.tests), ['a', 'aa', 'ab', 'root']); + }); + + test('initializes with valid counts', () => { + assert.deepStrictEqual(r.counts, { + ...makeEmptyCounts(), + [TestRunState.Unset]: 4 + }); + }); + + test('setAllToState', () => { + r.setAllToState({ state: TestRunState.Queued, duration: 0, messages: [] }, t => t.item.label !== 'root'); + assert.deepStrictEqual(r.counts, { + ...makeEmptyCounts(), + [TestRunState.Unset]: 1, + [TestRunState.Queued]: 3, + }); + + assert.deepStrictEqual(r.getStateByExtId('root\0a')?.state.state, TestRunState.Queued); + assert.deepStrictEqual(getLabelsIn(changed), ['a', 'aa', 'ab', 'root']); + }); + + test('updateState', () => { + r.updateState('1', { state: TestRunState.Running, duration: 0, messages: [] }); + assert.deepStrictEqual(r.counts, { + ...makeEmptyCounts(), + [TestRunState.Running]: 1, + [TestRunState.Unset]: 3, + }); + assert.deepStrictEqual(r.getStateByExtId('root\0a')?.state.state, TestRunState.Running); + // update computed state: + assert.deepStrictEqual(r.getStateByExtId('root')?.computedState, TestRunState.Running); + assert.deepStrictEqual(getLabelsIn(changed), ['a', 'root']); + }); + + test('retire', () => { + r.retire('root\0a'); + assert.deepStrictEqual(getLabelsIn(changed), ['a', 'aa', 'ab']); + assert.deepStrictEqual(getLabelsIn(retired), ['a']); + + retired.clear(); + changed.clear(); + + r.retire('root\0a'); + assert.deepStrictEqual(getLabelsIn(changed), []); + assert.deepStrictEqual(getLabelsIn(retired), []); + }); + + test('addTestToRun', () => { + r.updateState('4', { state: TestRunState.Running, duration: 0, messages: [] }); + assert.deepStrictEqual(r.counts, { + ...makeEmptyCounts(), + [TestRunState.Running]: 1, + [TestRunState.Unset]: 4, + }); + assert.deepStrictEqual(r.getStateByExtId('root\0b')?.state.state, TestRunState.Running); + // update computed state: + assert.deepStrictEqual(r.getStateByExtId('root')?.computedState, TestRunState.Running); + }); + + test('markComplete', () => { + r.setAllToState({ state: TestRunState.Queued, duration: 0, messages: [] }, t => true); + r.updateState('2', { state: TestRunState.Passed, duration: 0, messages: [] }); + changed.clear(); + + r.markComplete(); + + assert.deepStrictEqual(r.counts, { + ...makeEmptyCounts(), + [TestRunState.Passed]: 1, + [TestRunState.Unset]: 3, + }); + + assert.deepStrictEqual(r.getStateByExtId('root')?.state.state, TestRunState.Unset); + assert.deepStrictEqual(r.getStateByExtId('root\0a\0aa')?.state.state, TestRunState.Passed); + }); + }); + + suite('service', () => { + let storage: TestStorageService; + let results: TestResultService; + + setup(() => { + storage = new TestStorageService(); + results = new TestResultService( + new MockContextKeyService(), + storage, + ); + }); + + test('pushes new result', () => { + results.push(r); + assert.deepStrictEqual(results.results, [r]); + }); + + test('serializes and re-hydrates', () => { + results.push(r); + r.updateState('2', { state: TestRunState.Passed, duration: 0, messages: [] }); + r.markComplete(); + + results = new TestResultService( + new MockContextKeyService(), + storage, + ); + + const [rehydrated, actual] = results.getStateByExtId('root')!; + const expected = r.getStateByExtId('root')!; + delete expected.state.duration; // delete undefined props that don't survive serialization + delete expected.item.location; + + assert.deepStrictEqual(actual, { ...expected, retired: true }); + assert.deepStrictEqual(rehydrated.counts, r.counts); + assert.strictEqual(rehydrated.isComplete, true); + }); + + test('clears results but keeps ongoing tests', () => { + results.push(r); + r.markComplete(); + + const r2 = results.push(LiveTestResult.from( + [getInitializedMainTestCollection()], + [{ providerId: 'provider', testId: '1' }] + )); + results.clear(); + + assert.deepStrictEqual(results.results, [r2]); + }); + + test('keeps ongoing tests on top', () => { + results.push(r); + const r2 = results.push(LiveTestResult.from( + [getInitializedMainTestCollection()], + [{ providerId: 'provider', testId: '1' }] + )); + + assert.deepStrictEqual(results.results, [r2, r]); + r2.markComplete(); + assert.deepStrictEqual(results.results, [r, r2]); + r.markComplete(); + assert.deepStrictEqual(results.results, [r, r2]); + }); + }); +}); From a16f5d2c4c198cc887c814ccde54a1abe7a60eab Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 12 Feb 2021 18:11:50 +0100 Subject: [PATCH 073/325] fixes #116395 --- src/vs/workbench/services/label/common/labelService.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/services/label/common/labelService.ts b/src/vs/workbench/services/label/common/labelService.ts index c9fc28409c0..550b36e9726 100644 --- a/src/vs/workbench/services/label/common/labelService.ts +++ b/src/vs/workbench/services/label/common/labelService.ts @@ -21,7 +21,6 @@ import { match } from 'vs/base/common/glob'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IPathService } from 'vs/workbench/services/path/common/pathService'; -import { hasDriveLetter } from 'vs/base/common/extpath'; const resourceLabelFormattersExtPoint = ExtensionsRegistry.registerExtensionPoint({ extensionPoint: 'resourceLabelFormatters', @@ -74,6 +73,10 @@ const resourceLabelFormattersExtPoint = ExtensionsRegistry.registerExtensionPoin const sepRegexp = /\//g; const labelMatchingRegexp = /\$\{(scheme|authority|path|(query)\.(.+?))\}/g; +function hasDriveLetterIgnorePlatform(path: string): boolean { + return !!(path && path[2] === ':'); +} + class ResourceLabelFormattersHandler implements IWorkbenchContribution { private formattersDisposables = new Map(); @@ -283,7 +286,7 @@ export class LabelService extends Disposable implements ILabelService { }); // convert \c:\something => C:\something - if (formatting.normalizeDriveLetter && hasDriveLetter(label.substr(1))) { + if (formatting.normalizeDriveLetter && hasDriveLetterIgnorePlatform(label)) { label = label.charAt(1).toUpperCase() + label.substr(2); } From 14669c2e45731995833b9598ee087020fa006972 Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Fri, 12 Feb 2021 09:05:31 -0800 Subject: [PATCH 074/325] Make scopes parameter optional to getSessions and remove getAllSessions --- .../github-authentication/src/extension.ts | 3 +-- .../github-authentication/src/github.ts | 6 ++++-- .../microsoft-authentication/src/AADHelper.ts | 6 +++++- .../microsoft-authentication/src/extension.ts | 1 - src/vs/vscode.proposed.d.ts | 20 ++++++++----------- .../api/browser/mainThreadAuthentication.ts | 6 +----- .../workbench/api/common/extHost.protocol.ts | 3 +-- .../api/common/extHostAuthentication.ts | 11 +--------- .../parts/activitybar/activitybarActions.ts | 2 +- .../issue/electron-sandbox/issueService.ts | 2 +- .../contrib/url/browser/trustedDomains.ts | 2 +- .../browser/authenticationService.ts | 14 ++----------- .../browser/userDataSyncWorkbenchService.ts | 2 +- 13 files changed, 27 insertions(+), 51 deletions(-) diff --git a/extensions/github-authentication/src/extension.ts b/extensions/github-authentication/src/extension.ts index c9b76d81670..df80913cd22 100644 --- a/extensions/github-authentication/src/extension.ts +++ b/extensions/github-authentication/src/extension.ts @@ -24,8 +24,7 @@ export async function activate(context: vscode.ExtensionContext) { context.subscriptions.push(vscode.authentication.registerAuthenticationProvider('github', 'GitHub', { onDidChangeSessions: onDidChangeSessions.event, - getAllSessions: () => Promise.resolve(loginService.sessions), - getSessions: (scopes: string[]) => loginService.getSessions(scopes), + getSessions: (scopes?: string[]) => loginService.getSessions(scopes), createSession: async (scopeList: string[]) => { try { /* __GDPR__ diff --git a/extensions/github-authentication/src/github.ts b/extensions/github-authentication/src/github.ts index 89893c94ccd..bf6cee27132 100644 --- a/extensions/github-authentication/src/github.ts +++ b/extensions/github-authentication/src/github.ts @@ -44,8 +44,10 @@ export class GitHubAuthenticationProvider { context.subscriptions.push(context.secrets.onDidChange(() => this.checkForUpdates())); } - async getSessions(scopes: string[]): Promise { - return this._sessions.filter(session => arrayEquals(session.scopes, scopes)); + async getSessions(scopes?: string[]): Promise { + return scopes + ? this._sessions.filter(session => arrayEquals(session.scopes, scopes)) + : this._sessions; } private async verifySessions(): Promise { diff --git a/extensions/microsoft-authentication/src/AADHelper.ts b/extensions/microsoft-authentication/src/AADHelper.ts index fbb4e10a0e8..b0631344346 100644 --- a/extensions/microsoft-authentication/src/AADHelper.ts +++ b/extensions/microsoft-authentication/src/AADHelper.ts @@ -300,7 +300,11 @@ export class AzureActiveDirectoryService { return Promise.all(this._tokens.map(token => this.convertToSession(token))); } - async getSessions(scopes: string[]): Promise { + async getSessions(scopes?: string[]): Promise { + if (!scopes) { + return this.sessions; + } + const orderedScopes = scopes.sort().join(' '); const matchingTokens = this._tokens.filter(token => token.scope === orderedScopes); return Promise.all(matchingTokens.map(token => this.convertToSession(token))); diff --git a/extensions/microsoft-authentication/src/extension.ts b/extensions/microsoft-authentication/src/extension.ts index 584a4027b64..41b8690f344 100644 --- a/extensions/microsoft-authentication/src/extension.ts +++ b/extensions/microsoft-authentication/src/extension.ts @@ -20,7 +20,6 @@ export async function activate(context: vscode.ExtensionContext) { context.subscriptions.push(vscode.authentication.registerAuthenticationProvider('microsoft', 'Microsoft', { onDidChangeSessions: onDidChangeSessions.event, - getAllSessions: () => Promise.resolve(loginService.sessions), getSessions: (scopes: string[]) => loginService.getSessions(scopes), createSession: async (scopes: string[]) => { try { diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index febf42232e6..dbad76952cb 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -64,29 +64,25 @@ declare module 'vscode' { readonly onDidChangeSessions: Event; /** - * Returns an array of current sessions. - * - * TODO @RMacfarlane finish deprecating this and remove it + * Get a list of sessions. + * @param scopes An optional list of scopes. If provided, the sessions returned should match + * these permissions, otherwise all sessions should be returned. + * @returns A promise that resolves to an array of authentication sessions. */ // eslint-disable-next-line vscode-dts-provider-naming - getAllSessions(): Thenable>; - - - /** - * Returns an array of current sessions. - */ - // eslint-disable-next-line vscode-dts-provider-naming - getSessions(scopes: string[]): Thenable>; + getSessions(scopes?: string[]): Thenable>; /** * Prompts a user to login. + * @param scopes A list of scopes, permissions, that the new session should be created with. + * @returns A promise that resolves to an authentication session. */ // eslint-disable-next-line vscode-dts-provider-naming createSession(scopes: string[]): Thenable; /** * Removes the session corresponding to session id. - * @param sessionId The session id to log out of + * @param sessionId The id of the session to remove. */ // eslint-disable-next-line vscode-dts-provider-naming removeSession(sessionId: string): Thenable; diff --git a/src/vs/workbench/api/browser/mainThreadAuthentication.ts b/src/vs/workbench/api/browser/mainThreadAuthentication.ts index dfad0388642..64f7d14880f 100644 --- a/src/vs/workbench/api/browser/mainThreadAuthentication.ts +++ b/src/vs/workbench/api/browser/mainThreadAuthentication.ts @@ -89,14 +89,10 @@ export class MainThreadAuthenticationProvider extends Disposable { } } - async getSessions(scopes: string[]) { + async getSessions(scopes?: string[]) { return this._proxy.$getSessions(this.id, scopes); } - async getAllSessions(): Promise> { - return this._proxy.$getAllSessions(this.id); - } - createSession(scopes: string[]): Promise { return this._proxy.$createSession(this.id, scopes); } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 9e121b2c822..a55a0c041a1 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1125,8 +1125,7 @@ export interface ExtHostLabelServiceShape { } export interface ExtHostAuthenticationShape { - $getAllSessions(id: string): Promise>; - $getSessions(id: string, scopes: string[]): Promise>; + $getSessions(id: string, scopes?: string[]): Promise>; $createSession(id: string, scopes: string[]): Promise; $removeSession(id: string, sessionId: string): Promise; $onDidChangeAuthenticationSessions(id: string, label: string, event: modes.AuthenticationSessionsChangeEvent): Promise; diff --git a/src/vs/workbench/api/common/extHostAuthentication.ts b/src/vs/workbench/api/common/extHostAuthentication.ts index 988f93a5c9f..b4445864a7c 100644 --- a/src/vs/workbench/api/common/extHostAuthentication.ts +++ b/src/vs/workbench/api/common/extHostAuthentication.ts @@ -147,16 +147,7 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape { throw new Error(`Unable to find authentication provider with handle: ${providerId}`); } - $getAllSessions(providerId: string): Promise> { - const providerData = this._authenticationProviders.get(providerId); - if (providerData) { - return Promise.resolve(providerData.provider.getAllSessions()); - } - - throw new Error(`Unable to find authentication provider with handle: ${providerId}`); - } - - $getSessions(providerId: string, scopes: string[]): Promise> { + $getSessions(providerId: string, scopes?: string[]): Promise> { const providerData = this._authenticationProviders.get(providerId); if (providerData) { return Promise.resolve(providerData.provider.getSessions(scopes)); diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index c3f7817a47f..8b62c5a88de 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -210,7 +210,7 @@ export class AccountsActivityActionViewItem extends MenuActivityActionViewItem { const providers = this.authenticationService.getProviderIds(); const allSessions = providers.map(async providerId => { try { - const sessions = await this.authenticationService.getAllSessions(providerId); + const sessions = await this.authenticationService.getSessions(providerId); const groupedSessions: { [label: string]: AuthenticationSession[]; } = {}; sessions.forEach(session => { diff --git a/src/vs/workbench/contrib/issue/electron-sandbox/issueService.ts b/src/vs/workbench/contrib/issue/electron-sandbox/issueService.ts index 1deb2d639b0..94beb1646ae 100644 --- a/src/vs/workbench/contrib/issue/electron-sandbox/issueService.ts +++ b/src/vs/workbench/contrib/issue/electron-sandbox/issueService.ts @@ -54,7 +54,7 @@ export class WorkbenchIssueService implements IWorkbenchIssueService { }; }); const experiments = await this.experimentService.getCurrentExperiments(); - const githubSessions = await this.authenticationService.getAllSessions('github'); + const githubSessions = await this.authenticationService.getSessions('github'); const potentialSessions = githubSessions.filter(session => session.scopes.includes('repo')); const theme = this.themeService.getColorTheme(); const issueReporterData: IssueReporterData = Object.assign({ diff --git a/src/vs/workbench/contrib/url/browser/trustedDomains.ts b/src/vs/workbench/contrib/url/browser/trustedDomains.ts index b5188bfb036..145afdf032c 100644 --- a/src/vs/workbench/contrib/url/browser/trustedDomains.ts +++ b/src/vs/workbench/contrib/url/browser/trustedDomains.ts @@ -206,7 +206,7 @@ export async function readWorkspaceTrustedDomains(accessor: ServicesAccessor): P export async function readAuthenticationTrustedDomains(accessor: ServicesAccessor): Promise { const authenticationService = accessor.get(IAuthenticationService); - return authenticationService.isAuthenticationProviderRegistered('github') && ((await authenticationService.getAllSessions('github')) ?? []).length > 0 + return authenticationService.isAuthenticationProviderRegistered('github') && ((await authenticationService.getSessions('github')) ?? []).length > 0 ? [`https://github.com`] : []; } diff --git a/src/vs/workbench/services/authentication/browser/authenticationService.ts b/src/vs/workbench/services/authentication/browser/authenticationService.ts index 5d6de318988..6c1efc704be 100644 --- a/src/vs/workbench/services/authentication/browser/authenticationService.ts +++ b/src/vs/workbench/services/authentication/browser/authenticationService.ts @@ -124,8 +124,7 @@ export interface IAuthenticationService { declaredProviders: AuthenticationProviderInformation[]; readonly onDidChangeDeclaredProviders: Event; - getSessions(id: string, scopes: string[], activateImmediate?: boolean): Promise>; - getAllSessions(providerId: string, activateImmediate?: boolean): Promise>; + getSessions(id: string, scopes?: string[], activateImmediate?: boolean): Promise>; getLabel(providerId: string): string; supportsMultipleAccounts(providerId: string): boolean; createSession(providerId: string, scopes: string[], activateImmediate?: boolean): Promise; @@ -694,16 +693,7 @@ export class AuthenticationService extends Disposable implements IAuthentication return Promise.race([didRegister, didTimeout]); } - async getAllSessions(id: string, activateImmediate: boolean = false): Promise> { - try { - const authProvider = this._authenticationProviders.get(id) || await this.tryActivateProvider(id, activateImmediate); - return await authProvider.getAllSessions(); - } catch (_) { - throw new Error(`No authentication provider '${id}' is currently registered.`); - } - } - - async getSessions(id: string, scopes: string[], activateImmediate: boolean = false): Promise> { + async getSessions(id: string, scopes?: string[], activateImmediate: boolean = false): Promise> { try { const authProvider = this._authenticationProviders.get(id) || await this.tryActivateProvider(id, activateImmediate); return await authProvider.getSessions(scopes); diff --git a/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts b/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts index 32228c4c3b0..81afe84f97c 100644 --- a/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts +++ b/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts @@ -202,7 +202,7 @@ export class UserDataSyncWorkbenchService extends Disposable implements IUserDat let accounts: Map = new Map(); let currentAccount: UserDataSyncAccount | null = null; - const sessions = await this.authenticationService.getAllSessions(authenticationProviderId) || []; + const sessions = await this.authenticationService.getSessions(authenticationProviderId) || []; for (const session of sessions) { const account: UserDataSyncAccount = new UserDataSyncAccount(authenticationProviderId, session); accounts.set(account.accountName, account); From c83064b9825429ee327a9f9b3cf8928b735b5350 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 12 Feb 2021 09:18:27 -0800 Subject: [PATCH 075/325] Update freshExecArgv comment, fix #116422 --- .../services/search/electron-browser/searchService.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/vs/workbench/services/search/electron-browser/searchService.ts b/src/vs/workbench/services/search/electron-browser/searchService.ts index 09160857d0f..9e1f8f3f913 100644 --- a/src/vs/workbench/services/search/electron-browser/searchService.ts +++ b/src/vs/workbench/services/search/electron-browser/searchService.ts @@ -61,10 +61,7 @@ export class DiskSearch implements ISearchResultProvider { serverName: 'Search', timeout, args: ['--type=searchService'], - // See https://github.com/microsoft/vscode/issues/27665 // Pass in fresh execArgv to the forked process such that it doesn't inherit them from `process.execArgv`. - // e.g. Launching the extension host process with `--inspect-brk=xxx` and then forking a process from the extension host - // results in the forked process inheriting `--inspect-brk=xxx`. freshExecArgv: true, env: { VSCODE_AMD_ENTRYPOINT: 'vs/workbench/services/search/node/searchApp', From 888752f924178796ff8165531b896b244b9dc24c Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 09:31:57 -0800 Subject: [PATCH 076/325] remove node-pty from web --- remote/web/package.json | 1 - remote/web/yarn.lock | 12 ------------ 2 files changed, 13 deletions(-) diff --git a/remote/web/package.json b/remote/web/package.json index 577b0cbbb8d..6084e4460cc 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -5,7 +5,6 @@ "dependencies": { "iconv-lite-umd": "0.6.8", "jschardet": "2.2.1", - "node-pty": "0.10.0-beta19", "tas-client-umd": "0.1.2", "vscode-oniguruma": "1.3.1", "vscode-textmate": "5.2.0", diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index f69cbd4d1fc..9bcfb3b1e72 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -12,18 +12,6 @@ jschardet@2.2.1: resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-2.2.1.tgz#03b0264669a90c7a5c436a68c5a7d4e4cb0c9823" integrity sha512-Ks2JNuUJoc7PGaZ7bVFtSEvOcr0rBq6Q1J5/7+zKWLT+g+4zziL63O0jg7y2jxhzIa1LVsHUbPXrbaWmz9iwDw== -nan@^2.14.0: - version "2.14.2" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" - integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== - -node-pty@0.10.0-beta19: - version "0.10.0-beta19" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.0-beta19.tgz#b7cbfba53f7b2a816efe8c9302dd083cc5874458" - integrity sha512-4UIOGMvpofUbe+ZniBUtY8zc/psMURSzbMonQgIhK7JlMQsUwcbkDIrKzStVLJX0FkeZpUNlsVtK7qqzHvrUZA== - dependencies: - nan "^2.14.0" - tas-client-umd@0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/tas-client-umd/-/tas-client-umd-0.1.2.tgz#fe93ae085f65424292ac79feff4f1add3e50e624" From 52f633d19ce5479f4082df3e512d5489f054f5e4 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 12 Feb 2021 17:54:26 +0100 Subject: [PATCH 077/325] some :lipstick:, some API todos --- extensions/vscode-api-tests/src/utils.ts | 18 +++++++++++++++++- src/vs/vscode.proposed.d.ts | 4 ++++ .../api/browser/mainThreadNotebook.ts | 1 - .../notebook/browser/notebookServiceImpl.ts | 3 +++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/extensions/vscode-api-tests/src/utils.ts b/extensions/vscode-api-tests/src/utils.ts index f7923bbc9f7..a102e7d2329 100644 --- a/extensions/vscode-api-tests/src/utils.ts +++ b/extensions/vscode-api-tests/src/utils.ts @@ -17,7 +17,7 @@ vscode.workspace.registerFileSystemProvider(testFs.scheme, testFs, { isCaseSensi export async function createRandomFile(contents = '', dir: vscode.Uri | undefined = undefined, ext = ''): Promise { let fakeFile: vscode.Uri; if (dir) { - assert.equal(dir.scheme, testFs.scheme); + assert.strictEqual(dir.scheme, testFs.scheme); fakeFile = dir.with({ path: dir.path + '/' + rndName() + ext }); } else { fakeFile = vscode.Uri.parse(`${testFs.scheme}:/${rndName() + ext}`); @@ -117,3 +117,19 @@ export function assertNoRpcFromEntry(entry: [obj: any, name: string]) { assert.strictEqual(rpcPaths.length, 0, rpcPaths.join('\n')); assert.strictEqual(proxyPaths.length, 0, proxyPaths.join('\n')); // happens... } + +export async function asPromise(event: vscode.Event, timeout = 1000): Promise { + return new Promise((resolve, reject) => { + + const handle = setTimeout(() => { + sub.dispose(); + reject(new Error('asPromise TIMEOUT reached')); + }, timeout); + + const sub = event(e => { + clearTimeout(handle); + sub.dispose(); + resolve(e); + }); + }); +} diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index dbad76952cb..0122b4e2b2a 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1105,6 +1105,7 @@ declare module 'vscode' { readonly uri: Uri; readonly version: number; readonly fileName: string; + // todo@API should we really expose this? readonly viewType: string; readonly isDirty: boolean; readonly isUntitled: boolean; @@ -1305,6 +1306,8 @@ declare module 'vscode' { export namespace notebook { + // todo@API should we really support to pass the viewType? We do NOT support + // to open the same file with different viewTypes at the same time export function openNotebookDocument(uri: Uri, viewType?: string): Thenable; export const onDidOpenNotebookDocument: Event; export const onDidCloseNotebookDocument: Event; @@ -1330,6 +1333,7 @@ declare module 'vscode' { export const onDidChangeActiveNotebookEditor: Event; export const onDidChangeNotebookEditorSelection: Event; export const onDidChangeNotebookEditorVisibleRanges: Event; + // TODO@API add overload for just a URI export function showNotebookDocument(document: NotebookDocument, options?: NotebookDocumentShowOptions): Thenable; } diff --git a/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts index 812b2bed3f4..871641799f6 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -501,7 +501,6 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo const disposable = this._notebookService.registerNotebookController(viewType, extension, controller); this._notebookProviders.set(viewType, { controller, disposable }); - return; } async $updateNotebookProviderOptions(viewType: string, options?: { transientOutputs: boolean; transientMetadata: TransientMetadata; }): Promise { diff --git a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts index 3e6484a7baa..3aabfc323aa 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts @@ -680,6 +680,9 @@ export class NotebookService extends Disposable implements INotebookService, ICu } registerNotebookController(viewType: string, extensionData: NotebookExtensionDescription, controller: IMainNotebookController): IDisposable { + if (this._notebookProviders.has(viewType)) { + throw new Error(`notebook controller for viewtype '${viewType}' already exists`); + } this._notebookProviders.set(viewType, { extensionData, controller }); if (controller.viewOptions && !this.notebookProviderInfoStore.get(viewType)) { From 1f1db8515ee160dc2453b85394167639849c9c4d Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 12 Feb 2021 18:29:49 +0100 Subject: [PATCH 078/325] while resolving an editor input it might get disposed --- .../notebook/browser/notebookEditorInput.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorInput.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorInput.ts index 80bb8e33897..cd68acce0ec 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorInput.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorInput.ts @@ -160,11 +160,12 @@ ${patterns} if (!this._textModel) { this._textModel = await this._notebookModelResolverService.resolve(this.resource, this.viewType!); - - this._register(this._textModel.object.onDidChangeDirty(() => { - this._onDidChangeDirty.fire(); - })); - + if (this.isDisposed()) { + this._textModel.dispose(); + this._textModel = null; + return null; + } + this._register(this._textModel.object.onDidChangeDirty(() => this._onDidChangeDirty.fire())); if (this._textModel.object.isDirty()) { this._onDidChangeDirty.fire(); } @@ -185,10 +186,8 @@ ${patterns} } dispose() { - if (this._textModel) { - this._textModel.dispose(); - this._textModel = null; - } + this._textModel?.dispose(); + this._textModel = null; super.dispose(); } } From 5f9f03e822621be9d96feb6f30f7f2899df6b5be Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 12 Feb 2021 18:32:55 +0100 Subject: [PATCH 079/325] disable extensions when debugging API tests --- .vscode/launch.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 11c578b992d..b1db49c2549 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -110,7 +110,8 @@ // "${workspaceFolder}", // Uncomment for running out of sources. "${workspaceFolder}/extensions/vscode-api-tests/testWorkspace", "--extensionDevelopmentPath=${workspaceFolder}/extensions/vscode-api-tests", - "--extensionTestsPath=${workspaceFolder}/extensions/vscode-api-tests/out/singlefolder-tests" + "--extensionTestsPath=${workspaceFolder}/extensions/vscode-api-tests/out/singlefolder-tests", + "--disable-extensions" ], "outFiles": [ "${workspaceFolder}/out/**/*.js" From 2d6c2d0b2d793760c77cd8618d03248db259ae8c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 12 Feb 2021 19:17:03 +0100 Subject: [PATCH 080/325] wip - move notebook integration test into our normal API test extension --- extensions/vscode-api-tests/package.json | 21 + .../notebook.document.test.ts | 235 ++++++++ .../src/singlefolder-tests}/notebook.test.ts | 531 ++++++++---------- extensions/vscode-notebook-tests/package.json | 10 - .../src/notebookTestMain.ts | 122 ---- 5 files changed, 487 insertions(+), 432 deletions(-) create mode 100644 extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts rename extensions/{vscode-notebook-tests/src => vscode-api-tests/src/singlefolder-tests}/notebook.test.ts (81%) diff --git a/extensions/vscode-api-tests/package.json b/extensions/vscode-api-tests/package.json index 228a9681278..7e576805d5c 100644 --- a/extensions/vscode-api-tests/package.json +++ b/extensions/vscode-api-tests/package.json @@ -116,6 +116,27 @@ } ] } + ], + "notebookProvider": [ + { + "viewType": "notebookCoreTest", + "displayName": "Notebook Core Test", + "selector": [ + { + "filenamePattern": "*.vsctestnb", + "excludeFileNamePattern": "" + } + ] + }, + { + "viewType": "notebook.nbdtest", + "displayName": "notebook.nbdtest", + "selector": [ + { + "filenamePattern": "**/*.nbdtest" + } + ] + } ] }, "scripts": { diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts new file mode 100644 index 00000000000..cf9bd87bd24 --- /dev/null +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts @@ -0,0 +1,235 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import * as vscode from 'vscode'; +import { createRandomFile, disposeAll, asPromise, closeAllEditors, assertNoRpc } from '../utils'; + +suite('Notebook Document', function () { + + const contentProvider = new class implements vscode.NotebookContentProvider { + async openNotebook(uri: vscode.Uri, _openContext: vscode.NotebookDocumentOpenContext): Promise { + return { + cells: [{ cellKind: vscode.NotebookCellKind.Code, source: uri.toString(), language: 'javascript', metadata: {}, outputs: [] }], + metadata: {} + }; + } + async resolveNotebook(_document: vscode.NotebookDocument, _webview: vscode.NotebookCommunication) { + // + } + async saveNotebook(_document: vscode.NotebookDocument, _cancellation: vscode.CancellationToken) { + // + } + async saveNotebookAs(_targetResource: vscode.Uri, _document: vscode.NotebookDocument, _cancellation: vscode.CancellationToken) { + // + } + async backupNotebook(_document: vscode.NotebookDocument, _context: vscode.NotebookDocumentBackupContext, _cancellation: vscode.CancellationToken) { + return { id: '', delete() { } }; + } + }; + + const disposables: vscode.Disposable[] = []; + + suiteTeardown(async function () { + assertNoRpc(); + await vscode.commands.executeCommand('workbench.action.files.saveAll'); + await closeAllEditors(); + disposeAll(disposables); + disposables.length = 0; + + for (let doc of vscode.notebook.notebookDocuments) { + assert.strictEqual(doc.isDirty, false) + } + }); + + suiteSetup(function () { + disposables.push(vscode.notebook.registerNotebookContentProvider('notebook.nbdtest', contentProvider)); + }); + + test('cannot register sample provider multiple times', function () { + assert.throws(() => { + vscode.notebook.registerNotebookContentProvider('notebook.nbdtest', contentProvider); + }); + }); + + test('cannot open unknown types', async function () { + try { + await vscode.notebook.openNotebookDocument(vscode.Uri.parse('some:///thing.notTypeKnown')); + assert.ok(false); + } catch { + assert.ok(true); + } + }); + + test('document basics', async function () { + const uri = await createRandomFile(undefined, undefined, '.nbdtest'); + const notebook = await vscode.notebook.openNotebookDocument(uri); + + assert.strictEqual(notebook.uri.toString(), uri.toString()); + assert.strictEqual(notebook.isDirty, false); + assert.strictEqual(notebook.isUntitled, false); + assert.strictEqual(notebook.cells.length, 1); + + assert.strictEqual(notebook.viewType, 'notebook.nbdtest'); + }); + + test('notebook open/close, notebook ready when cell-document open event is fired', async function () { + const uri = await createRandomFile(undefined, undefined, '.nbdtest'); + let didHappen = false; + const p = asPromise(vscode.workspace.onDidOpenTextDocument).then(doc => { + if (doc.uri.scheme !== 'vscode-notebook-cell') { + return; + } + const notebook = vscode.notebook.notebookDocuments.find(notebook => { + const cell = notebook.cells.find(cell => cell.document === doc); + return Boolean(cell); + }); + assert.ok(notebook, `notebook for cell ${doc.uri} NOT found`); + didHappen = true; + }); + + await vscode.notebook.openNotebookDocument(uri); + await p; + assert.strictEqual(didHappen, true); + }); + + test('notebook open/close, all cell-documents are ready', async function () { + const uri = await createRandomFile(undefined, undefined, '.nbdtest'); + + const p = asPromise(vscode.notebook.onDidOpenNotebookDocument).then(notebook => { + for (let cell of notebook.cells) { + const doc = vscode.workspace.textDocuments.find(doc => doc.uri.toString() === cell.uri.toString()); + assert.ok(doc); + assert.strictEqual(doc.notebook === notebook, true); + assert.strictEqual(doc === cell.document, true); + assert.strictEqual(doc?.languageId, cell.language); + assert.strictEqual(doc?.isDirty, false); + assert.strictEqual(doc?.isClosed, false); + } + }); + + await vscode.notebook.openNotebookDocument(uri); + await p; + }); + + + test('workspace edit API (replaceCells)', async function () { + const uri = await createRandomFile(undefined, undefined, '.nbdtest'); + + const document = await vscode.notebook.openNotebookDocument(uri); + assert.strictEqual(document.cells.length, 1); + + // inserting two new cells + { + const edit = new vscode.WorkspaceEdit(); + edit.replaceNotebookCells(document.uri, 0, 0, [{ + cellKind: vscode.NotebookCellKind.Markdown, + language: 'markdown', + metadata: undefined, + outputs: [], + source: 'new_markdown' + }, { + cellKind: vscode.NotebookCellKind.Code, + language: 'fooLang', + metadata: undefined, + outputs: [], + source: 'new_code' + }]); + + const success = await vscode.workspace.applyEdit(edit); + assert.strictEqual(success, true); + } + + assert.strictEqual(document.cells.length, 3); + assert.strictEqual(document.cells[0].document.getText(), 'new_markdown'); + assert.strictEqual(document.cells[1].document.getText(), 'new_code'); + + // deleting cell 1 and 3 + { + const edit = new vscode.WorkspaceEdit(); + edit.replaceNotebookCells(document.uri, 0, 1, []); + edit.replaceNotebookCells(document.uri, 2, 3, []); + const success = await vscode.workspace.applyEdit(edit); + assert.strictEqual(success, true); + } + + assert.strictEqual(document.cells.length, 1); + assert.strictEqual(document.cells[0].document.getText(), 'new_code'); + + // replacing all cells + { + const edit = new vscode.WorkspaceEdit(); + edit.replaceNotebookCells(document.uri, 0, 1, [{ + cellKind: vscode.NotebookCellKind.Markdown, + language: 'markdown', + metadata: undefined, + outputs: [], + source: 'new2_markdown' + }, { + cellKind: vscode.NotebookCellKind.Code, + language: 'fooLang', + metadata: undefined, + outputs: [], + source: 'new2_code' + }]); + const success = await vscode.workspace.applyEdit(edit); + assert.strictEqual(success, true); + } + assert.strictEqual(document.cells.length, 2); + assert.strictEqual(document.cells[0].document.getText(), 'new2_markdown'); + assert.strictEqual(document.cells[1].document.getText(), 'new2_code'); + + // remove all cells + { + const edit = new vscode.WorkspaceEdit(); + edit.replaceNotebookCells(document.uri, 0, document.cells.length, []); + const success = await vscode.workspace.applyEdit(edit); + assert.strictEqual(success, true); + } + assert.strictEqual(document.cells.length, 0); + }); + + test('workspace edit API (replaceCells, event)', async function () { + const uri = await createRandomFile(undefined, undefined, '.nbdtest'); + const document = await vscode.notebook.openNotebookDocument(uri); + assert.strictEqual(document.cells.length, 1); + + const edit = new vscode.WorkspaceEdit(); + edit.replaceNotebookCells(document.uri, 0, 0, [{ + cellKind: vscode.NotebookCellKind.Markdown, + language: 'markdown', + metadata: undefined, + outputs: [], + source: 'new_markdown' + }, { + cellKind: vscode.NotebookCellKind.Code, + language: 'fooLang', + metadata: undefined, + outputs: [], + source: 'new_code' + }]); + + const event = asPromise(vscode.notebook.onDidChangeNotebookCells); + + const success = await vscode.workspace.applyEdit(edit); + assert.strictEqual(success, true); + + const data = await event; + + // check document + assert.strictEqual(document.cells.length, 3); + assert.strictEqual(document.cells[0].document.getText(), 'new_markdown'); + assert.strictEqual(document.cells[1].document.getText(), 'new_code'); + + // check event data + assert.strictEqual(data.document === document, true); + assert.strictEqual(data.changes.length, 1); + assert.strictEqual(data.changes[0].deletedCount, 0); + assert.strictEqual(data.changes[0].deletedItems.length, 0); + assert.strictEqual(data.changes[0].items.length, 2); + assert.strictEqual(data.changes[0].items[0], document.cells[0]); + assert.strictEqual(data.changes[0].items[1], document.cells[1]); + }); +}); diff --git a/extensions/vscode-notebook-tests/src/notebook.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts similarity index 81% rename from extensions/vscode-notebook-tests/src/notebook.test.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts index 0117e41160a..7db8c7784d6 100644 --- a/extensions/vscode-notebook-tests/src/notebook.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts @@ -6,52 +6,13 @@ import 'mocha'; import * as assert from 'assert'; import * as vscode from 'vscode'; -import { createRandomFile } from './utils'; - -export function timeoutAsync(n: number): Promise { - return new Promise(resolve => { - setTimeout(() => { - resolve(); - }, n); - }); -} - -export function once(event: vscode.Event): vscode.Event { - return (listener: any, thisArgs = null, disposables?: any) => { - // we need this, in case the event fires during the listener call - let didFire = false; - let result: vscode.Disposable; - result = event(e => { - if (didFire) { - return; - } else if (result) { - result.dispose(); - } else { - didFire = true; - } - - return listener.call(thisArgs, e); - }, null, disposables); - - if (didFire) { - result.dispose(); - } - - return result; - }; -} - -async function getEventOncePromise(event: vscode.Event): Promise { - return new Promise((resolve, _reject) => { - once(event)((result: T) => resolve(result)); - }); -} +import { createRandomFile, asPromise, disposeAll, closeAllEditors } from '../utils'; // Since `workbench.action.splitEditor` command does await properly // Notebook editor/document events are not guaranteed to be sent to the ext host when promise resolves // The workaround here is waiting for the first visible notebook editor change event. async function splitEditor() { - const once = getEventOncePromise(vscode.window.onDidChangeVisibleNotebookEditors); + const once = asPromise(vscode.window.onDidChangeVisibleNotebookEditors); await vscode.commands.executeCommand('workbench.action.splitEditor'); await once; } @@ -100,7 +61,7 @@ async function updateNotebookMetadata(uri: vscode.Uri, newMetadata: vscode.Noteb } async function withEvent(event: vscode.Event, callback: (e: Promise) => Promise) { - const e = getEventOncePromise(event); + const e = asPromise(event); await callback(e); } @@ -112,7 +73,144 @@ function assertInitalState() { // assert.strictEqual(vscode.notebook.visibleNotebookEditors.length, 0); } -suite('Notebook API tests', () => { +suite('Notebook API tests', function () { + + const disposables: vscode.Disposable[] = []; + + suiteTeardown(async function () { + disposeAll(disposables); + await vscode.commands.executeCommand('workbench.action.files.saveAll'); + await closeAllEditors(); + }); + + suiteSetup(function () { + disposables.push(vscode.notebook.registerNotebookContentProvider('notebookCoreTest', { + openNotebook: async (_resource: vscode.Uri): Promise => { + if (/.*empty\-.*\.vsctestnb$/.test(_resource.path)) { + return { + metadata: {}, + cells: [] + }; + } + + const dto: vscode.NotebookData = { + metadata: { + custom: { testMetadata: false } + }, + cells: [ + { + source: 'test', + language: 'typescript', + cellKind: vscode.NotebookCellKind.Code, + outputs: [], + metadata: { + custom: { testCellMetadata: 123 } + } + } + ] + }; + return dto; + }, + resolveNotebook: async (_document: vscode.NotebookDocument) => { + return; + }, + saveNotebook: async (_document: vscode.NotebookDocument, _cancellation: vscode.CancellationToken) => { + return; + }, + saveNotebookAs: async (_targetResource: vscode.Uri, _document: vscode.NotebookDocument, _cancellation: vscode.CancellationToken) => { + return; + }, + backupNotebook: async (_document: vscode.NotebookDocument, _context: vscode.NotebookDocumentBackupContext, _cancellation: vscode.CancellationToken) => { + return { + id: '1', + delete: () => { } + }; + } + })); + + + const kernel: vscode.NotebookKernel = { + id: 'mainKernel', + label: 'Notebook Test Kernel', + isPreferred: true, + supportedLanguages: ['typescript'], + executeAllCells: async (_document: vscode.NotebookDocument) => { + const edit = new vscode.WorkspaceEdit(); + + edit.replaceNotebookCellOutput(_document.uri, 0, [new vscode.NotebookCellOutput([ + new vscode.NotebookCellOutputItem('text/plain', ['my output'], undefined) + ])]); + return vscode.workspace.applyEdit(edit); + }, + cancelAllCellsExecution: async (_document: vscode.NotebookDocument) => { }, + executeCell: async (document: vscode.NotebookDocument, cell: vscode.NotebookCell | undefined) => { + if (!cell) { + cell = document.cells[0]; + } + + if (document.uri.path.endsWith('customRenderer.vsctestnb')) { + const edit = new vscode.WorkspaceEdit(); + edit.replaceNotebookCellOutput(document.uri, cell.index, [new vscode.NotebookCellOutput([ + new vscode.NotebookCellOutputItem('text/custom', ['test'], undefined) + ])]); + + return vscode.workspace.applyEdit(edit); + } + + const edit = new vscode.WorkspaceEdit(); + // const previousOutputs = cell.outputs; + edit.replaceNotebookCellOutput(document.uri, cell.index, [new vscode.NotebookCellOutput([ + new vscode.NotebookCellOutputItem('text/plain', ['my output'], undefined) + ])]); + + return vscode.workspace.applyEdit(edit); + }, + cancelCellExecution: async (_document: vscode.NotebookDocument, _cell: vscode.NotebookCell) => { } + }; + + const kernel2: vscode.NotebookKernel = { + id: 'secondaryKernel', + label: 'Notebook Secondary Test Kernel', + isPreferred: false, + supportedLanguages: ['typescript'], + executeAllCells: async (_document: vscode.NotebookDocument) => { + const edit = new vscode.WorkspaceEdit(); + edit.replaceNotebookCellOutput(_document.uri, 0, [new vscode.NotebookCellOutput([ + new vscode.NotebookCellOutputItem('text/plain', ['my second output'], undefined) + ])]); + + return vscode.workspace.applyEdit(edit); + }, + cancelAllCellsExecution: async (_document: vscode.NotebookDocument) => { }, + executeCell: async (document: vscode.NotebookDocument, cell: vscode.NotebookCell | undefined) => { + if (!cell) { + cell = document.cells[0]; + } + + const edit = new vscode.WorkspaceEdit(); + + if (document.uri.path.endsWith('customRenderer.vsctestnb')) { + edit.replaceNotebookCellOutput(document.uri, cell.index, [new vscode.NotebookCellOutput([ + new vscode.NotebookCellOutputItem('text/custom', ['test 2'], undefined) + ])]); + } else { + edit.replaceNotebookCellOutput(document.uri, cell.index, [new vscode.NotebookCellOutput([ + new vscode.NotebookCellOutputItem('text/plain', ['my second output'], undefined) + ])]); + } + + return vscode.workspace.applyEdit(edit); + }, + cancelCellExecution: async (_document: vscode.NotebookDocument, _cell: vscode.NotebookCell) => { } + }; + + disposables.push(vscode.notebook.registerNotebookKernelProvider({ filenamePattern: '*.vsctestnb' }, { + provideKernels: async () => { + return [kernel, kernel2]; + } + })); + }); + // test.only('crash', async function () { // for (let i = 0; i < 200; i++) { // let resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb')); @@ -141,60 +239,20 @@ suite('Notebook API tests', () => { test('document open/close event', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); - const firstDocumentOpen = getEventOncePromise(vscode.notebook.onDidOpenNotebookDocument); + const resource = await createRandomFile('', undefined, '.vsctestnb'); + const firstDocumentOpen = asPromise(vscode.notebook.onDidOpenNotebookDocument); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); await firstDocumentOpen; - const firstDocumentClose = getEventOncePromise(vscode.notebook.onDidCloseNotebookDocument); + const firstDocumentClose = asPromise(vscode.notebook.onDidCloseNotebookDocument); await vscode.commands.executeCommand('workbench.action.closeAllEditors'); await firstDocumentClose; }); - test('notebook open/close, all cell-documents are ready', async function () { - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); - - const p = getEventOncePromise(vscode.notebook.onDidOpenNotebookDocument).then(notebook => { - for (let cell of notebook.cells) { - const doc = vscode.workspace.textDocuments.find(doc => doc.uri.toString() === cell.uri.toString()); - assert.ok(doc); - assert.strictEqual(doc === cell.document, true); - assert.strictEqual(doc?.languageId, cell.language); - assert.strictEqual(doc?.isDirty, false); - assert.strictEqual(doc?.isClosed, false); - } - }); - - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - await p; - await vscode.commands.executeCommand('workbench.action.closeAllEditors'); - }); - - test('notebook open/close, notebook ready when cell-document open event is fired', async function () { - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); - let didHappen = false; - const p = getEventOncePromise(vscode.workspace.onDidOpenTextDocument).then(doc => { - if (doc.uri.scheme !== 'vscode-notebook-cell') { - return; - } - const notebook = vscode.notebook.notebookDocuments.find(notebook => { - const cell = notebook.cells.find(cell => cell.document === doc); - return Boolean(cell); - }); - assert.ok(notebook, `notebook for cell ${doc.uri} NOT found`); - didHappen = true; - }); - - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - await p; - assert.strictEqual(didHappen, true); - await vscode.commands.executeCommand('workbench.action.closeAllEditors'); - }); - test('shared document in notebook editors', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); let counter = 0; const disposables: vscode.Disposable[] = []; disposables.push(vscode.notebook.onDidOpenNotebookDocument(() => { @@ -217,12 +275,12 @@ suite('Notebook API tests', () => { test('editor open/close event', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); - const firstEditorOpen = getEventOncePromise(vscode.window.onDidChangeVisibleNotebookEditors); + const resource = await createRandomFile('', undefined, '.vsctestnb'); + const firstEditorOpen = asPromise(vscode.window.onDidChangeVisibleNotebookEditors); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); await firstEditorOpen; - const firstEditorClose = getEventOncePromise(vscode.window.onDidChangeVisibleNotebookEditors); + const firstEditorClose = asPromise(vscode.window.onDidChangeVisibleNotebookEditors); await vscode.commands.executeCommand('workbench.action.closeAllEditors'); await firstEditorClose; }); @@ -230,7 +288,7 @@ suite('Notebook API tests', () => { test('editor open/close event 2', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); let count = 0; const disposables: vscode.Disposable[] = []; disposables.push(vscode.window.onDidChangeVisibleNotebookEditors(() => { @@ -250,10 +308,10 @@ suite('Notebook API tests', () => { test('editor editing event 2', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - const cellsChangeEvent = getEventOncePromise(vscode.notebook.onDidChangeNotebookCells); + const cellsChangeEvent = asPromise(vscode.notebook.onDidChangeNotebookCells); await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); const cellChangeEventRet = await cellsChangeEvent; assert.strictEqual(cellChangeEventRet.document, vscode.window.activeNotebookEditor?.document); @@ -269,7 +327,7 @@ suite('Notebook API tests', () => { const secondCell = vscode.window.activeNotebookEditor!.document.cells[1]; - const moveCellEvent = getEventOncePromise(vscode.notebook.onDidChangeNotebookCells); + const moveCellEvent = asPromise(vscode.notebook.onDidChangeNotebookCells); await vscode.commands.executeCommand('notebook.cell.moveUp'); const moveCellEventRet = await moveCellEvent; assert.deepStrictEqual(moveCellEventRet, { @@ -290,7 +348,7 @@ suite('Notebook API tests', () => { ] }); - const cellOutputChange = getEventOncePromise(vscode.notebook.onDidChangeCellOutputs); + const cellOutputChange = asPromise(vscode.notebook.onDidChangeCellOutputs); await vscode.commands.executeCommand('notebook.cell.execute'); const cellOutputsAddedRet = await cellOutputChange; assert.deepStrictEqual(cellOutputsAddedRet, { @@ -299,7 +357,7 @@ suite('Notebook API tests', () => { }); assert.strictEqual(cellOutputsAddedRet.cells[0].outputs.length, 1); - const cellOutputClear = getEventOncePromise(vscode.notebook.onDidChangeCellOutputs); + const cellOutputClear = asPromise(vscode.notebook.onDidChangeCellOutputs); await vscode.commands.executeCommand('notebook.cell.clearOutputs'); const cellOutputsCleardRet = await cellOutputClear; assert.deepStrictEqual(cellOutputsCleardRet, { @@ -323,7 +381,7 @@ suite('Notebook API tests', () => { test('editor move cell event', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove'); @@ -331,7 +389,7 @@ suite('Notebook API tests', () => { const activeCell = vscode.window.activeNotebookEditor!.selection; assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.indexOf(activeCell!), 0); - const moveChange = getEventOncePromise(vscode.notebook.onDidChangeNotebookCells); + const moveChange = asPromise(vscode.notebook.onDidChangeNotebookCells); await vscode.commands.executeCommand('notebook.cell.moveDown'); const ret = await moveChange; assert.deepStrictEqual(ret, { @@ -365,7 +423,7 @@ suite('Notebook API tests', () => { test('notebook editor active/visible', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); const firstEditor = vscode.window.activeNotebookEditor; assert.strictEqual(firstEditor && vscode.window.visibleNotebookEditors.indexOf(firstEditor) >= 0, true); @@ -377,7 +435,7 @@ suite('Notebook API tests', () => { assert.strictEqual(firstEditor && vscode.window.visibleNotebookEditors.indexOf(firstEditor) >= 0, true); assert.strictEqual(vscode.window.visibleNotebookEditors.length, 2); - const untitledEditorChange = getEventOncePromise(vscode.window.onDidChangeActiveNotebookEditor); + const untitledEditorChange = asPromise(vscode.window.onDidChangeActiveNotebookEditor); await vscode.commands.executeCommand('workbench.action.files.newUntitledFile'); await untitledEditorChange; assert.strictEqual(firstEditor && vscode.window.visibleNotebookEditors.indexOf(firstEditor) >= 0, true); @@ -386,7 +444,7 @@ suite('Notebook API tests', () => { assert.notStrictEqual(secondEditor, vscode.window.activeNotebookEditor); assert.strictEqual(vscode.window.visibleNotebookEditors.length, 1); - const activeEditorClose = getEventOncePromise(vscode.window.onDidChangeActiveNotebookEditor); + const activeEditorClose = asPromise(vscode.window.onDidChangeActiveNotebookEditor); await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); await activeEditorClose; assert.strictEqual(secondEditor, vscode.window.activeNotebookEditor); @@ -399,12 +457,12 @@ suite('Notebook API tests', () => { test('notebook active editor change', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); - const firstEditorOpen = getEventOncePromise(vscode.window.onDidChangeActiveNotebookEditor); + const resource = await createRandomFile('', undefined, '.vsctestnb'); + const firstEditorOpen = asPromise(vscode.window.onDidChangeActiveNotebookEditor); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); await firstEditorOpen; - const firstEditorDeactivate = getEventOncePromise(vscode.window.onDidChangeActiveNotebookEditor); + const firstEditorDeactivate = asPromise(vscode.window.onDidChangeActiveNotebookEditor); await vscode.commands.executeCommand('workbench.action.splitEditor'); await firstEditorDeactivate; @@ -413,10 +471,10 @@ suite('Notebook API tests', () => { test('edit API (replaceCells)', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - const cellsChangeEvent = getEventOncePromise(vscode.notebook.onDidChangeNotebookCells); + const cellsChangeEvent = asPromise(vscode.notebook.onDidChangeNotebookCells); await vscode.window.activeNotebookEditor!.edit(editBuilder => { editBuilder.replaceCells(1, 0, [{ cellKind: vscode.NotebookCellKind.Code, language: 'javascript', source: 'test 2', outputs: [], metadata: undefined }]); }); @@ -434,7 +492,7 @@ suite('Notebook API tests', () => { test('edit API (replaceOutput, USE NotebookCellOutput-type)', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); await vscode.window.activeNotebookEditor!.edit(editBuilder => { @@ -463,7 +521,7 @@ suite('Notebook API tests', () => { test('edit API (replaceOutput)', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); await vscode.window.activeNotebookEditor!.edit(editBuilder => { @@ -485,10 +543,10 @@ suite('Notebook API tests', () => { test('edit API (replaceOutput, event)', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - const outputChangeEvent = getEventOncePromise(vscode.notebook.onDidChangeCellOutputs); + const outputChangeEvent = asPromise(vscode.notebook.onDidChangeCellOutputs); await vscode.window.activeNotebookEditor!.edit(editBuilder => { editBuilder.replaceCellOutput(0, [new vscode.NotebookCellOutput([ new vscode.NotebookCellOutputItem('foo', 'bar') @@ -511,7 +569,7 @@ suite('Notebook API tests', () => { test('edit API (replaceMetadata)', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); await vscode.window.activeNotebookEditor!.edit(editBuilder => { @@ -530,10 +588,10 @@ suite('Notebook API tests', () => { test('edit API (replaceMetadata, event)', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - const event = getEventOncePromise(vscode.notebook.onDidChangeCellMetadata); + const event = asPromise(vscode.notebook.onDidChangeCellMetadata); await vscode.window.activeNotebookEditor!.edit(editBuilder => { editBuilder.replaceCellMetadata(0, { inputCollapsed: true, executionOrder: 17 }); @@ -548,141 +606,13 @@ suite('Notebook API tests', () => { await saveFileAndCloseAll(resource); }); - test('workspace edit API (replaceCells)', async function () { - - assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - - const { document } = vscode.window.activeNotebookEditor!; - assert.strictEqual(document.cells.length, 1); - - // inserting two new cells - { - const edit = new vscode.WorkspaceEdit(); - edit.replaceNotebookCells(document.uri, 0, 0, [{ - cellKind: vscode.NotebookCellKind.Markdown, - language: 'markdown', - metadata: undefined, - outputs: [], - source: 'new_markdown' - }, { - cellKind: vscode.NotebookCellKind.Code, - language: 'fooLang', - metadata: undefined, - outputs: [], - source: 'new_code' - }]); - - const success = await vscode.workspace.applyEdit(edit); - assert.strictEqual(success, true); - } - - assert.strictEqual(document.cells.length, 3); - assert.strictEqual(document.cells[0].document.getText(), 'new_markdown'); - assert.strictEqual(document.cells[1].document.getText(), 'new_code'); - - // deleting cell 1 and 3 - { - const edit = new vscode.WorkspaceEdit(); - edit.replaceNotebookCells(document.uri, 0, 1, []); - edit.replaceNotebookCells(document.uri, 2, 3, []); - const success = await vscode.workspace.applyEdit(edit); - assert.strictEqual(success, true); - } - - assert.strictEqual(document.cells.length, 1); - assert.strictEqual(document.cells[0].document.getText(), 'new_code'); - - // replacing all cells - { - const edit = new vscode.WorkspaceEdit(); - edit.replaceNotebookCells(document.uri, 0, 1, [{ - cellKind: vscode.NotebookCellKind.Markdown, - language: 'markdown', - metadata: undefined, - outputs: [], - source: 'new2_markdown' - }, { - cellKind: vscode.NotebookCellKind.Code, - language: 'fooLang', - metadata: undefined, - outputs: [], - source: 'new2_code' - }]); - const success = await vscode.workspace.applyEdit(edit); - assert.strictEqual(success, true); - } - assert.strictEqual(document.cells.length, 2); - assert.strictEqual(document.cells[0].document.getText(), 'new2_markdown'); - assert.strictEqual(document.cells[1].document.getText(), 'new2_code'); - - // remove all cells - { - const edit = new vscode.WorkspaceEdit(); - edit.replaceNotebookCells(document.uri, 0, document.cells.length, []); - const success = await vscode.workspace.applyEdit(edit); - assert.strictEqual(success, true); - } - assert.strictEqual(document.cells.length, 0); - - await saveFileAndCloseAll(resource); - }); - - test('workspace edit API (replaceCells, event)', async function () { - - assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - - const { document } = vscode.window.activeNotebookEditor!; - assert.strictEqual(document.cells.length, 1); - - const edit = new vscode.WorkspaceEdit(); - edit.replaceNotebookCells(document.uri, 0, 0, [{ - cellKind: vscode.NotebookCellKind.Markdown, - language: 'markdown', - metadata: undefined, - outputs: [], - source: 'new_markdown' - }, { - cellKind: vscode.NotebookCellKind.Code, - language: 'fooLang', - metadata: undefined, - outputs: [], - source: 'new_code' - }]); - - const event = getEventOncePromise(vscode.notebook.onDidChangeNotebookCells); - - const success = await vscode.workspace.applyEdit(edit); - assert.strictEqual(success, true); - - const data = await event; - - // check document - assert.strictEqual(document.cells.length, 3); - assert.strictEqual(document.cells[0].document.getText(), 'new_markdown'); - assert.strictEqual(document.cells[1].document.getText(), 'new_code'); - - // check event data - assert.strictEqual(data.document === document, true); - assert.strictEqual(data.changes.length, 1); - assert.strictEqual(data.changes[0].deletedCount, 0); - assert.strictEqual(data.changes[0].deletedItems.length, 0); - assert.strictEqual(data.changes[0].items.length, 2); - assert.strictEqual(data.changes[0].items[0], document.cells[0]); - assert.strictEqual(data.changes[0].items[1], document.cells[1]); - await saveFileAndCloseAll(resource); - }); - test('edit API batch edits', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - const cellsChangeEvent = getEventOncePromise(vscode.notebook.onDidChangeNotebookCells); - const cellMetadataChangeEvent = getEventOncePromise(vscode.notebook.onDidChangeCellMetadata); + const cellsChangeEvent = asPromise(vscode.notebook.onDidChangeNotebookCells); + const cellMetadataChangeEvent = asPromise(vscode.notebook.onDidChangeCellMetadata); const version = vscode.window.activeNotebookEditor!.document.version; await vscode.window.activeNotebookEditor!.edit(editBuilder => { editBuilder.replaceCells(1, 0, [{ cellKind: vscode.NotebookCellKind.Code, language: 'javascript', source: 'test 2', outputs: [], metadata: undefined }]); @@ -697,11 +627,11 @@ suite('Notebook API tests', () => { test('edit API batch edits undo/redo', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - const cellsChangeEvent = getEventOncePromise(vscode.notebook.onDidChangeNotebookCells); - const cellMetadataChangeEvent = getEventOncePromise(vscode.notebook.onDidChangeCellMetadata); + const cellsChangeEvent = asPromise(vscode.notebook.onDidChangeNotebookCells); + const cellMetadataChangeEvent = asPromise(vscode.notebook.onDidChangeCellMetadata); const version = vscode.window.activeNotebookEditor!.document.version; await vscode.window.activeNotebookEditor!.edit(editBuilder => { editBuilder.replaceCells(1, 0, [{ cellKind: vscode.NotebookCellKind.Code, language: 'javascript', source: 'test 2', outputs: [], metadata: undefined }]); @@ -724,7 +654,7 @@ suite('Notebook API tests', () => { test('initialzation should not emit cell change events.', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); let count = 0; const disposables: vscode.Disposable[] = []; @@ -739,12 +669,13 @@ suite('Notebook API tests', () => { await saveFileAndCloseAll(resource); }); -}); + // }); + + // suite('notebook workflow', () => { -suite('notebook workflow', () => { test('notebook open', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.document.getText(), 'test'); @@ -766,7 +697,7 @@ suite('notebook workflow', () => { test('notebook cell actions', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.document.getText(), 'test'); @@ -840,7 +771,7 @@ suite('notebook workflow', () => { test('notebook join cells', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.document.getText(), 'test'); @@ -852,7 +783,7 @@ suite('notebook workflow', () => { edit.insert(vscode.window.activeNotebookEditor!.selection!.uri, new vscode.Position(0, 0), 'var abc = 0;'); await vscode.workspace.applyEdit(edit); - const cellsChangeEvent = getEventOncePromise(vscode.notebook.onDidChangeNotebookCells); + const cellsChangeEvent = asPromise(vscode.notebook.onDidChangeNotebookCells); await vscode.commands.executeCommand('notebook.cell.joinAbove'); await cellsChangeEvent; @@ -864,7 +795,7 @@ suite('notebook workflow', () => { test('move cells will not recreate cells in ExtHost', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove'); @@ -884,7 +815,7 @@ suite('notebook workflow', () => { }); // test.only('document metadata is respected', async function () { - // const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + // const resource = await createRandomFile('', undefined, '.vsctestnb'); // await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); // assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); @@ -909,7 +840,7 @@ suite('notebook workflow', () => { test('cell runnable metadata is respected', async () => { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); const editor = vscode.window.activeNotebookEditor!; @@ -918,14 +849,14 @@ suite('notebook workflow', () => { const cell = editor.document.cells[0]; assert.strictEqual(cell.outputs.length, 0); - let metadataChangeEvent = getEventOncePromise(vscode.notebook.onDidChangeCellMetadata); + let metadataChangeEvent = asPromise(vscode.notebook.onDidChangeCellMetadata); await updateCellMetadata(resource, cell, { ...cell.metadata, runnable: false }); await metadataChangeEvent; await vscode.commands.executeCommand('notebook.cell.execute'); assert.strictEqual(cell.outputs.length, 0, 'should not execute'); // not runnable, didn't work - metadataChangeEvent = getEventOncePromise(vscode.notebook.onDidChangeCellMetadata); + metadataChangeEvent = asPromise(vscode.notebook.onDidChangeCellMetadata); await updateCellMetadata(resource, cell, { ...cell.metadata, runnable: true }); await metadataChangeEvent; @@ -938,7 +869,7 @@ suite('notebook workflow', () => { test('document runnable metadata is respected', async () => { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); const editor = vscode.window.activeNotebookEditor!; @@ -973,7 +904,7 @@ suite('notebook workflow', () => { // TODO@rebornix this is wrong, `await vscode.commands.executeCommand('notebook.execute');` doesn't wait until the workspace edit is applied test.skip('cell execute command takes arguments', async () => { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); const editor = vscode.window.activeNotebookEditor!; @@ -988,7 +919,7 @@ suite('notebook workflow', () => { test('cell execute command takes arguments 2', async () => { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); const editor = vscode.window.activeNotebookEditor!; @@ -1011,7 +942,7 @@ suite('notebook workflow', () => { assert.strictEqual(cell.outputs.length, 0, 'should clear'); }); - const secondResource = await createRandomFile('', undefined, 'second', '.vsctestnb'); + const secondResource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest'); await withEvent(vscode.notebook.onDidChangeCellOutputs, async (event) => { @@ -1029,13 +960,13 @@ suite('notebook workflow', () => { test('document execute command takes arguments', async () => { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); const editor = vscode.window.activeNotebookEditor!; const cell = editor.document.cells[0]; - const metadataChangeEvent = getEventOncePromise(vscode.notebook.onDidChangeNotebookDocumentMetadata); + const metadataChangeEvent = asPromise(vscode.notebook.onDidChangeNotebookDocumentMetadata); updateNotebookMetadata(editor.document.uri, { ...editor.document.metadata, runnable: true }); await metadataChangeEvent; assert.strictEqual(editor.document.metadata.runnable, true); @@ -1046,12 +977,12 @@ suite('notebook workflow', () => { assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked }); - const clearChangeEvent = getEventOncePromise(vscode.notebook.onDidChangeCellOutputs); + const clearChangeEvent = asPromise(vscode.notebook.onDidChangeCellOutputs); await vscode.commands.executeCommand('notebook.cell.clearOutputs'); await clearChangeEvent; assert.strictEqual(cell.outputs.length, 0, 'should clear'); - const secondResource = await createRandomFile('', undefined, 'second', '.vsctestnb'); + const secondResource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest'); await withEvent(vscode.notebook.onDidChangeCellOutputs, async (event) => { @@ -1069,13 +1000,13 @@ suite('notebook workflow', () => { test('cell execute and select kernel', async () => { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); const editor = vscode.window.activeNotebookEditor!; const cell = editor.document.cells[0]; - const metadataChangeEvent = getEventOncePromise(vscode.notebook.onDidChangeNotebookDocumentMetadata); + const metadataChangeEvent = asPromise(vscode.notebook.onDidChangeNotebookDocumentMetadata); updateNotebookMetadata(editor.document.uri, { ...editor.document.metadata, runnable: true }); await metadataChangeEvent; @@ -1087,7 +1018,7 @@ suite('notebook workflow', () => { 'my output' ]); - await vscode.commands.executeCommand('notebook.selectKernel', { extension: 'vscode.vscode-notebook-tests', id: 'secondaryKernel' }); + await vscode.commands.executeCommand('notebook.selectKernel', { extension: 'vscode.vscode-api-tests', id: 'secondaryKernel' }); await vscode.commands.executeCommand('notebook.cell.execute'); assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked assert.strictEqual(cell.outputs[0].outputs.length, 1); @@ -1099,12 +1030,12 @@ suite('notebook workflow', () => { await vscode.commands.executeCommand('workbench.action.files.save'); await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); }); -}); + // }); -suite('notebook dirty state', () => { + // suite('notebook dirty state', () => { test('notebook open', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.document.getText(), 'test'); @@ -1133,12 +1064,12 @@ suite('notebook dirty state', () => { await saveFileAndCloseAll(resource); }); -}); + // }); -suite('notebook undo redo', () => { + // suite('notebook undo redo', () => { test('notebook open', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.document.getText(), 'test'); @@ -1181,7 +1112,7 @@ suite('notebook undo redo', () => { // test.skip('execute and then undo redo', async function () { // assertInitalState(); - // const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + // const resource = await createRandomFile('', undefined, '.vsctestnb'); // await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); // const cellsChangeEvent = getEventOncePromise(vscode.notebook.onDidChangeNotebookCells); @@ -1242,11 +1173,11 @@ suite('notebook undo redo', () => { // await saveFileAndCloseAll(resource); // }); -}); + // }); -suite('notebook working copy', () => { + // suite('notebook working copy', () => { // test('notebook revert on close', async function () { - // const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + // const resource = await createRandomFile('', undefined, '.vsctestnb'); // await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); // await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); // assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.document.getText(), ''); @@ -1267,7 +1198,7 @@ suite('notebook working copy', () => { // }); // test('notebook revert', async function () { - // const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + // const resource = await createRandomFile('', undefined, '.vsctestnb'); // await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); // await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); // assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.document.getText(), ''); @@ -1288,7 +1219,7 @@ suite('notebook working copy', () => { test('multiple tabs: dirty + clean', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.document.getText(), ''); @@ -1298,7 +1229,7 @@ suite('notebook working copy', () => { edit.insert(vscode.window.activeNotebookEditor!.selection!.uri, new vscode.Position(0, 0), 'var abc = 0;'); await vscode.workspace.applyEdit(edit); - const secondResource = await createRandomFile('', undefined, 'second', '.vsctestnb'); + const secondResource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest'); await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); @@ -1314,7 +1245,7 @@ suite('notebook working copy', () => { test('multiple tabs: two dirty tabs and switching', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.document.getText(), ''); @@ -1324,7 +1255,7 @@ suite('notebook working copy', () => { edit.insert(vscode.window.activeNotebookEditor!.selection!.uri, new vscode.Position(0, 0), 'var abc = 0;'); await vscode.workspace.applyEdit(edit); - const secondResource = await createRandomFile('', undefined, 'second', '.vsctestnb'); + const secondResource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest'); await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.document.getText(), ''); @@ -1353,7 +1284,7 @@ suite('notebook working copy', () => { test('multiple tabs: different editors with same document', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); const firstNotebookEditor = vscode.window.activeNotebookEditor; assert.strictEqual(firstNotebookEditor !== undefined, true, 'notebook first'); @@ -1375,12 +1306,12 @@ suite('notebook working copy', () => { // await vscode.commands.executeCommand('workbench.action.files.saveAll'); // await vscode.commands.executeCommand('workbench.action.closeAllEditors'); }); -}); + // }); -suite('metadata', () => { + // suite('metadata', () => { test('custom metadata should be supported', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); assert.strictEqual(vscode.window.activeNotebookEditor!.document.metadata.custom!['testMetadata'] as boolean, false); @@ -1394,7 +1325,7 @@ suite('metadata', () => { // TODO@rebornix skip as it crashes the process all the time test.skip('custom metadata should be supported 2', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); assert.strictEqual(vscode.window.activeNotebookEditor!.document.metadata.custom!['testMetadata'] as boolean, false); @@ -1409,9 +1340,9 @@ suite('metadata', () => { await saveFileAndCloseAll(resource); }); -}); + // }); -suite('regression', () => { + // suite('regression', () => { // test('microsoft/vscode-github-issue-notebooks#26. Insert template cell in the new empty document', async function () { // assertInitalState(); // await vscode.commands.executeCommand('workbench.action.files.newUntitledFile', { "viewType": "notebookCoreTest" }); @@ -1423,7 +1354,7 @@ suite('regression', () => { test('#106657. Opening a notebook from markers view is broken ', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); const document = vscode.window.activeNotebookEditor?.document!; @@ -1441,7 +1372,7 @@ suite('regression', () => { test.skip('Cannot open notebook from cell-uri with vscode.open-command', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); const document = vscode.window.activeNotebookEditor?.document!; @@ -1459,7 +1390,7 @@ suite('regression', () => { test('#97830, #97764. Support switch to other editor types', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'empty', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); const edit = new vscode.WorkspaceEdit(); @@ -1485,7 +1416,7 @@ suite('regression', () => { // open text editor, pin, and then open a notebook test('#96105 - dirty editors', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'empty', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'default'); const edit = new vscode.WorkspaceEdit(); edit.insert(resource, new vscode.Position(0, 0), 'var abc = 0;'); @@ -1509,7 +1440,7 @@ suite('regression', () => { test('#102423 - copy/paste shares the same text buffer', async function () { assertInitalState(); - const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); let activeCell = vscode.window.activeNotebookEditor!.selection; @@ -1530,16 +1461,16 @@ suite('regression', () => { await vscode.commands.executeCommand('workbench.action.closeAllEditors'); }); -}); + // }); -suite('webview', () => { + // suite('webview', () => { // for web, `asWebUri` gets `https`? // test('asWebviewUri', async function () { // if (vscode.env.uiKind === vscode.UIKind.Web) { // return; // } - // const resource = await createRandomFile('', undefined, 'first', '.vsctestnb'); + // const resource = await createRandomFile('', undefined, '.vsctestnb'); // await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); // assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); // const uri = vscode.window.activeNotebookEditor!.asWebviewUri(vscode.Uri.file('./hello.png')); diff --git a/extensions/vscode-notebook-tests/package.json b/extensions/vscode-notebook-tests/package.json index 0451ebf9283..153ce130e24 100644 --- a/extensions/vscode-notebook-tests/package.json +++ b/extensions/vscode-notebook-tests/package.json @@ -34,16 +34,6 @@ } ], "notebookProvider": [ - { - "viewType": "notebookCoreTest", - "displayName": "Notebook Core Test", - "selector": [ - { - "filenamePattern": "*.vsctestnb", - "excludeFileNamePattern": "" - } - ] - }, { "viewType": "notebookSmokeTest", "displayName": "Notebook Smoke Test", diff --git a/extensions/vscode-notebook-tests/src/notebookTestMain.ts b/extensions/vscode-notebook-tests/src/notebookTestMain.ts index c856d19e46c..8cf19b430be 100644 --- a/extensions/vscode-notebook-tests/src/notebookTestMain.ts +++ b/extensions/vscode-notebook-tests/src/notebookTestMain.ts @@ -9,128 +9,6 @@ import { smokeTestActivate } from './notebookSmokeTestMain'; export function activate(context: vscode.ExtensionContext): any { smokeTestActivate(context); - context.subscriptions.push(vscode.notebook.registerNotebookContentProvider('notebookCoreTest', { - openNotebook: async (_resource: vscode.Uri): Promise => { - if (/.*empty\-.*\.vsctestnb$/.test(_resource.path)) { - return { - metadata: {}, - cells: [] - }; - } - const dto: vscode.NotebookData = { - metadata: { - custom: { testMetadata: false } - }, - cells: [ - { - source: 'test', - language: 'typescript', - cellKind: vscode.NotebookCellKind.Code, - outputs: [], - metadata: { - custom: { testCellMetadata: 123 } - } - } - ] - }; - return dto; - }, - resolveNotebook: async (_document: vscode.NotebookDocument) => { - return; - }, - saveNotebook: async (_document: vscode.NotebookDocument, _cancellation: vscode.CancellationToken) => { - return; - }, - saveNotebookAs: async (_targetResource: vscode.Uri, _document: vscode.NotebookDocument, _cancellation: vscode.CancellationToken) => { - return; - }, - backupNotebook: async (_document: vscode.NotebookDocument, _context: vscode.NotebookDocumentBackupContext, _cancellation: vscode.CancellationToken) => { - return { - id: '1', - delete: () => { } - }; - } - })); - const kernel: vscode.NotebookKernel = { - id: 'mainKernel', - label: 'Notebook Test Kernel', - isPreferred: true, - supportedLanguages: ['typescript'], - executeAllCells: async (_document: vscode.NotebookDocument) => { - const edit = new vscode.WorkspaceEdit(); - - edit.replaceNotebookCellOutput(_document.uri, 0, [new vscode.NotebookCellOutput([ - new vscode.NotebookCellOutputItem('text/plain', ['my output'], undefined) - ])]); - return vscode.workspace.applyEdit(edit); - }, - cancelAllCellsExecution: async (_document: vscode.NotebookDocument) => { }, - executeCell: async (document: vscode.NotebookDocument, cell: vscode.NotebookCell | undefined) => { - if (!cell) { - cell = document.cells[0]; - } - - if (document.uri.path.endsWith('customRenderer.vsctestnb')) { - const edit = new vscode.WorkspaceEdit(); - edit.replaceNotebookCellOutput(document.uri, cell.index, [new vscode.NotebookCellOutput([ - new vscode.NotebookCellOutputItem('text/custom', ['test'], undefined) - ])]); - - return vscode.workspace.applyEdit(edit); - } - - const edit = new vscode.WorkspaceEdit(); - // const previousOutputs = cell.outputs; - edit.replaceNotebookCellOutput(document.uri, cell.index, [new vscode.NotebookCellOutput([ - new vscode.NotebookCellOutputItem('text/plain', ['my output'], undefined) - ])]); - - return vscode.workspace.applyEdit(edit); - }, - cancelCellExecution: async (_document: vscode.NotebookDocument, _cell: vscode.NotebookCell) => { } - }; - - const kernel2: vscode.NotebookKernel = { - id: 'secondaryKernel', - label: 'Notebook Secondary Test Kernel', - isPreferred: false, - supportedLanguages: ['typescript'], - executeAllCells: async (_document: vscode.NotebookDocument) => { - const edit = new vscode.WorkspaceEdit(); - edit.replaceNotebookCellOutput(_document.uri, 0, [new vscode.NotebookCellOutput([ - new vscode.NotebookCellOutputItem('text/plain', ['my second output'], undefined) - ])]); - - return vscode.workspace.applyEdit(edit); - }, - cancelAllCellsExecution: async (_document: vscode.NotebookDocument) => { }, - executeCell: async (document: vscode.NotebookDocument, cell: vscode.NotebookCell | undefined) => { - if (!cell) { - cell = document.cells[0]; - } - - const edit = new vscode.WorkspaceEdit(); - - if (document.uri.path.endsWith('customRenderer.vsctestnb')) { - edit.replaceNotebookCellOutput(document.uri, cell.index, [new vscode.NotebookCellOutput([ - new vscode.NotebookCellOutputItem('text/custom', ['test 2'], undefined) - ])]); - } else { - edit.replaceNotebookCellOutput(document.uri, cell.index, [new vscode.NotebookCellOutput([ - new vscode.NotebookCellOutputItem('text/plain', ['my second output'], undefined) - ])]); - } - - return vscode.workspace.applyEdit(edit); - }, - cancelCellExecution: async (_document: vscode.NotebookDocument, _cell: vscode.NotebookCell) => { } - }; - - context.subscriptions.push(vscode.notebook.registerNotebookKernelProvider({ filenamePattern: '*.vsctestnb' }, { - provideKernels: async () => { - return [kernel, kernel2]; - } - })); } From 8912ec1803a1e775d66eb51f409ed9a8e374fa5b Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 10:18:17 -0800 Subject: [PATCH 081/325] Move ptyService out of shared proc temporarily --- .../terminal/electron-browser/localPtyService.ts | 1 + src/vs/platform/terminal/node/ptyService.ts | 3 ++- .../electron-sandbox/terminal.contribution.ts | 11 ++++++++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/vs/platform/terminal/electron-browser/localPtyService.ts b/src/vs/platform/terminal/electron-browser/localPtyService.ts index 4944517f2d9..6e097451205 100644 --- a/src/vs/platform/terminal/electron-browser/localPtyService.ts +++ b/src/vs/platform/terminal/electron-browser/localPtyService.ts @@ -110,6 +110,7 @@ export class LocalPtyService extends Disposable implements IPtyService { dispose() { // this._isDisposed = true; + console.log('LocalPtyService.dispose'); super.dispose(); } diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index af4db72adb1..17b55d739e5 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -31,12 +31,13 @@ export class PtyService extends Disposable implements IPtyService { readonly onProcessResolvedShellLaunchConfig = this._onProcessResolvedShellLaunchConfig.event; constructor( - private readonly _logService: ILogService + @ILogService private readonly _logService: ILogService ) { super(); } dispose() { + console.log('PtyService.dispose'); for (const pty of this._ptys.values()) { pty.shutdown(true); } diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts index 181c5f37ab6..0c9f0ae675c 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts @@ -3,8 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { registerSharedProcessRemoteService } from 'vs/platform/ipc/electron-sandbox/services'; -import { TerminalIpcChannels } from 'vs/platform/terminal/common/terminal'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +// import { registerSharedProcessRemoteService } from 'vs/platform/ipc/electron-sandbox/services'; +// import { TerminalIpcChannels } from 'vs/platform/terminal/common/terminal'; import { ILocalPtyService } from 'vs/platform/terminal/electron-sandbox/terminal'; +// eslint-disable-next-line +import { PtyService } from 'vs/platform/terminal/node/ptyService'; -registerSharedProcessRemoteService(ILocalPtyService, TerminalIpcChannels.LocalPty, { supportsDelayedInstantiation: true }); +// registerSharedProcessRemoteService(ILocalPtyService, TerminalIpcChannels.LocalPty, { supportsDelayedInstantiation: true }); + +registerSingleton(ILocalPtyService, PtyService, true); From f1202da4a00a64d6fd685c22ec3b3de717a28673 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 12 Feb 2021 10:30:38 -0800 Subject: [PATCH 082/325] Simplify search view tree height calculation Fix #116182 --- .../contrib/search/browser/media/searchview.css | 11 +++++++++++ .../workbench/contrib/search/browser/searchView.ts | 12 +----------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/search/browser/media/searchview.css b/src/vs/workbench/contrib/search/browser/media/searchview.css index 896a356acac..057347da4d8 100644 --- a/src/vs/workbench/contrib/search/browser/media/searchview.css +++ b/src/vs/workbench/contrib/search/browser/media/searchview.css @@ -3,6 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +.search-view { + display: flex; + flex-direction: column; + height: 100%; +} + +.search-view .results { + flex-grow: 1; + min-height: 0; /* Allow it to be smaller than its contents */ +} + .search-view .search-widgets-container { margin: 0px 12px 0 2px; padding-top: 6px; diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index 40f36f73b52..8350e27ee2d 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -1038,17 +1038,7 @@ export class SearchView extends ViewPane { this.inputPatternExcludes.setWidth(this.size.width - 28 /* container margin */); this.inputPatternIncludes.setWidth(this.size.width - 28 /* container margin */); - const messagesSize = this.messagesElement.style.display === 'none' ? - 0 : - dom.getTotalHeight(this.messagesElement); - - const searchResultContainerHeight = this.size.height - - messagesSize - - dom.getTotalHeight(this.searchWidgetsContainerElement); - - this.resultsElement.style.height = searchResultContainerHeight + 'px'; - - this.tree.layout(searchResultContainerHeight, this.size.width); + this.tree.layout(); // The tree will measure its container } protected layoutBody(height: number, width: number): void { From 1f45db9994fd9d68759f5f397731c8e334845003 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 10:31:46 -0800 Subject: [PATCH 083/325] Disable api tests --- scripts/test-integration.bat | 4 ++-- scripts/test-integration.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/test-integration.bat b/scripts/test-integration.bat index 3013dc04b90..b09b61141ef 100644 --- a/scripts/test-integration.bat +++ b/scripts/test-integration.bat @@ -45,8 +45,8 @@ if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" ( :: Tests in the extension host -call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% -if %errorlevel% neq 0 exit /b %errorlevel% +::call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% +::if %errorlevel% neq 0 exit /b %errorlevel% call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% if %errorlevel% neq 0 exit /b %errorlevel% diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index b1d5e9588e3..ade423433ca 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -65,8 +65,8 @@ fi after_suite # Tests in the extension host -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR -after_suite +#"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR +#after_suite # TODO(deepak1556): Disable workspace test temporarily # https://github.com/microsoft/vscode/issues/111288 From 33d715555c15b70885222fa0726851b58f5f4987 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Fri, 12 Feb 2021 10:37:14 -0800 Subject: [PATCH 084/325] Remeove "Skip" link, ref #114964. --- .../contrib/welcome/gettingStarted/browser/gettingStarted.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts index cb7bcf8f3c9..ef8331f915d 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts @@ -324,7 +324,7 @@ export class GettingStartedPage extends EditorPane { const showOnStartupCheckbox = $('input.checkbox', { id: 'showOnStartup', type: 'checkbox' }) as HTMLInputElement; categoryScrollContainer.appendChild( $('.footer', {}, - $('button.skip.button-link', { 'x-dispatch': 'skip' }, localize('gettingStarted.skip', "Skip")), + // $('button.skip.button-link', { 'x-dispatch': 'skip' }, localize('gettingStarted.skip', "Skip")), $('p.showOnStartup', {}, showOnStartupCheckbox, $('label.caption', { for: 'showOnStartup' }, localize('welcomePage.showOnStartup', "Show Getting Started page on startup"))) From 0568d26fad687f580ff53350e8fd3bbf932b732f Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Fri, 12 Feb 2021 18:54:11 +0000 Subject: [PATCH 085/325] Revert "Support the new 4.0 definition of isArray (#102413)" (#116571) This reverts commit d47ddb670db0aaa025feba46f99d3bb84e6e25e1. --- src/vs/base/common/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/base/common/types.ts b/src/vs/base/common/types.ts index da93a17e08a..a91a3cfd174 100644 --- a/src/vs/base/common/types.ts +++ b/src/vs/base/common/types.ts @@ -8,7 +8,7 @@ import { URI, UriComponents } from 'vs/base/common/uri'; /** * @returns whether the provided parameter is a JavaScript Array or not. */ -export function isArray(array: T | {}): array is T extends readonly any[] ? (unknown extends T ? never : readonly any[]) : any[] { +export function isArray(array: any): array is any[] { return Array.isArray(array); } From 2e1166cb0c204c048de89eab009aaa8dec616ef2 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 11 Feb 2021 20:07:38 -0800 Subject: [PATCH 086/325] Make sure webview editor has not been disposed before claiming webview Fixes #115743 Also added an exception to make sure we don't call `show` on a disposed of webview editor overlay --- .../contrib/webview/browser/dynamicWebviewEditorOverlay.ts | 7 +++++++ .../contrib/webviewPanel/browser/webviewEditor.ts | 5 ++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts b/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts index d67cf68e348..102f7132e9c 100644 --- a/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts +++ b/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts @@ -60,10 +60,13 @@ export class DynamicWebviewEditorOverlay extends Disposable implements WebviewOv return !!this._webview.value?.isFocused; } + private _isDisposed = false; + private readonly _onDidDispose = this._register(new Emitter()); public onDidDispose = this._onDidDispose.event; dispose() { + this._isDisposed = true; this.container.remove(); this._onDidDispose.fire(); super.dispose(); @@ -138,6 +141,10 @@ export class DynamicWebviewEditorOverlay extends Disposable implements WebviewOv } private show() { + if (this._isDisposed) { + throw new Error('Webview overlay is disposed'); + } + if (!this._webview.value) { const webview = this._webviewService.createWebviewElement(this.id, this._options, this._contentOptions, this.extension); this._webview.value = webview; diff --git a/src/vs/workbench/contrib/webviewPanel/browser/webviewEditor.ts b/src/vs/workbench/contrib/webviewPanel/browser/webviewEditor.ts index 1eebb76e499..5a6f5253013 100644 --- a/src/vs/workbench/contrib/webviewPanel/browser/webviewEditor.ts +++ b/src/vs/workbench/contrib/webviewPanel/browser/webviewEditor.ts @@ -31,6 +31,7 @@ export class WebviewEditor extends EditorPane { private _element?: HTMLElement; private _dimension?: DOM.Dimension; private _visible = false; + private _isDisposed = false; private readonly _webviewVisibleDisposables = this._register(new DisposableStore()); private readonly _onFocusWindowHandler = this._register(new MutableDisposable()); @@ -71,6 +72,8 @@ export class WebviewEditor extends EditorPane { } public dispose(): void { + this._isDisposed = true; + if (this._element) { this._element.remove(); this._element = undefined; @@ -133,7 +136,7 @@ export class WebviewEditor extends EditorPane { await super.setInput(input, options, context, token); await input.resolve(); - if (token.isCancellationRequested) { + if (token.isCancellationRequested || this._isDisposed) { return; } From 2cb4179ec6ab930510e2595e1a982b333a224dc8 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 11 Feb 2021 20:25:39 -0800 Subject: [PATCH 087/325] Make sure the webview gets focused even if the actual webview content does not yet exist Fixes #112677 --- src/vs/workbench/contrib/webview/browser/pre/main.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/workbench/contrib/webview/browser/pre/main.js b/src/vs/workbench/contrib/webview/browser/pre/main.js index b2f093ee195..cc3bc25eab0 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/main.js +++ b/src/vs/workbench/contrib/webview/browser/pre/main.js @@ -446,6 +446,8 @@ host.onMessage('focus', () => { const activeFrame = getActiveFrame(); if (!activeFrame || !activeFrame.contentWindow) { + // Focus the top level webview instead + window.focus(); return; } From 27e1db98c128f99c52b5c93705ed064068642544 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 11 Feb 2021 20:25:59 -0800 Subject: [PATCH 088/325] Move some additional focus fixed from electron webviews to iframe webviews --- .../electron-sandbox/iframeWebviewElement.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/webview/electron-sandbox/iframeWebviewElement.ts b/src/vs/workbench/contrib/webview/electron-sandbox/iframeWebviewElement.ts index 672018e2ce4..5321866d575 100644 --- a/src/vs/workbench/contrib/webview/electron-sandbox/iframeWebviewElement.ts +++ b/src/vs/workbench/contrib/webview/electron-sandbox/iframeWebviewElement.ts @@ -128,8 +128,16 @@ export class ElectronIframeWebview extends IFrameWebview { return; } + // Clear the existing focus first if not already on the webview. + // This is required because the next part where we set the focus is async. + if (document.activeElement && document.activeElement instanceof HTMLElement && document.activeElement !== this.element) { + // Don't blur if on the webview because this will also happen async and may unset the focus + // after the focus trigger fires below. + document.activeElement.blur(); + } + // Workaround for https://github.com/microsoft/vscode/issues/75209 - // .focus is async for imframes so for a sequence of actions such as: + // Electron's webview.focus is async so for a sequence of actions such as: // // 1. Open webview // 1. Show quick pick from command palette @@ -143,8 +151,7 @@ export class ElectronIframeWebview extends IFrameWebview { if (!this.isFocused || !this.element) { return; } - - if (document.activeElement?.tagName === 'INPUT') { + if (document.activeElement && document.activeElement?.tagName !== 'BODY') { return; } try { From 44477fbb74ca47f2c87908b272ba07c6d61fc430 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 11:03:01 -0800 Subject: [PATCH 089/325] Re-enable tests, disable terminal suite --- .../vscode-api-tests/src/singlefolder-tests/terminal.test.ts | 2 +- scripts/test-integration.bat | 4 ++-- scripts/test-integration.sh | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index a24019b21fe..5775eaf674a 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -27,7 +27,7 @@ import { assertNoRpc } from '../utils'; await config.update('rendererType', 'dom', ConfigurationTarget.Global); }); - suite('Terminal', () => { + suite.skip('Terminal', () => { let disposables: Disposable[] = []; teardown(() => { diff --git a/scripts/test-integration.bat b/scripts/test-integration.bat index b09b61141ef..3013dc04b90 100644 --- a/scripts/test-integration.bat +++ b/scripts/test-integration.bat @@ -45,8 +45,8 @@ if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" ( :: Tests in the extension host -::call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% -::if %errorlevel% neq 0 exit /b %errorlevel% +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% +if %errorlevel% neq 0 exit /b %errorlevel% call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% if %errorlevel% neq 0 exit /b %errorlevel% diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index ade423433ca..b1d5e9588e3 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -65,8 +65,8 @@ fi after_suite # Tests in the extension host -#"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR -#after_suite +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR +after_suite # TODO(deepak1556): Disable workspace test temporarily # https://github.com/microsoft/vscode/issues/111288 From 6148fedea06945e4472548fb23a8883165cde258 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 11:34:17 -0800 Subject: [PATCH 090/325] Enable terminal tests that deal with ptys only --- .../src/singlefolder-tests/terminal.test.ts | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index 5775eaf674a..ee31b49cca5 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -27,7 +27,7 @@ import { assertNoRpc } from '../utils'; await config.update('rendererType', 'dom', ConfigurationTarget.Global); }); - suite.skip('Terminal', () => { + suite('Terminal', () => { let disposables: Disposable[] = []; teardown(() => { @@ -36,7 +36,7 @@ import { assertNoRpc } from '../utils'; disposables.length = 0; }); - test('sendText immediately after createTerminal should not throw', async () => { + test.skip('sendText immediately after createTerminal should not throw', async () => { const terminal = window.createTerminal(); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -57,7 +57,7 @@ import { assertNoRpc } from '../utils'; }); }); - (process.platform === 'linux' ? test.skip : test)('echo works in the default shell', (done) => { + (process.platform === 'linux' ? test.skip : test.skip)('echo works in the default shell', (done) => { disposables.push(window.onDidOpenTerminal(term => { try { equal(terminal, term); @@ -102,7 +102,7 @@ import { assertNoRpc } from '../utils'; }); }); - test('onDidCloseTerminal event fires when terminal is disposed', async () => { + test.skip('onDidCloseTerminal event fires when terminal is disposed', async () => { const terminal = window.createTerminal(); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -122,7 +122,7 @@ import { assertNoRpc } from '../utils'; }); }); - test('processId immediately after createTerminal should fetch the pid', async () => { + test.skip('processId immediately after createTerminal should fetch the pid', async () => { const terminal = window.createTerminal(); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -144,7 +144,7 @@ import { assertNoRpc } from '../utils'; }); }); - test('name in constructor should set terminal.name', async () => { + test.skip('name in constructor should set terminal.name', async () => { const terminal = window.createTerminal('a'); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -164,7 +164,7 @@ import { assertNoRpc } from '../utils'; }); }); - test('creationOptions should be set and readonly for TerminalOptions terminals', async () => { + test.skip('creationOptions should be set and readonly for TerminalOptions terminals', async () => { const options = { name: 'foo', hideFromUser: true @@ -190,7 +190,7 @@ import { assertNoRpc } from '../utils'; throws(() => terminalOptions.name = 'bad', 'creationOptions should be readonly at runtime'); }); - test('onDidOpenTerminal should fire when a terminal is created', async () => { + test.skip('onDidOpenTerminal should fire when a terminal is created', async () => { const terminal = window.createTerminal('b'); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -210,7 +210,7 @@ import { assertNoRpc } from '../utils'; }); }); - test('exitStatus.code should be set to undefined after a terminal is disposed', async () => { + test.skip('exitStatus.code should be set to undefined after a terminal is disposed', async () => { const terminal = window.createTerminal(); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -301,7 +301,7 @@ import { assertNoRpc } from '../utils'; // terminal1.show(); // }); - suite('hideFromUser', () => { + suite.skip('hideFromUser', () => { test('should be available to terminals API', async () => { const terminal = window.createTerminal({ name: 'bg', hideFromUser: true }); const result = await new Promise(r => { @@ -636,7 +636,7 @@ import { assertNoRpc } from '../utils'; }); }); - suite('environmentVariableCollection', () => { + suite.skip('environmentVariableCollection', () => { test('should have collection variables apply to terminals immediately after setting', (done) => { // Text to match on before passing the test const expectedText = [ From fab9533c5ce01fc32f44a53e75e789acac3796ea Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Fri, 12 Feb 2021 11:37:20 -0800 Subject: [PATCH 091/325] Add some aria roles ref #115896 --- .../gettingStarted/browser/gettingStarted.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts index ef8331f915d..d17e7d5c275 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts @@ -302,7 +302,9 @@ export class GettingStartedPage extends EditorPane { $('.category-description.description', { 'aria-label': category.description + ' ' + localize('pressEnterToSelect', "Press Enter to Select") }, category.description), $('.category-progress', { 'x-data-category-id': category.id, }, $('.message'), - $('.progress-bar-outer', {}, + $('.progress-bar-outer', { + 'role': 'progressbar' + }, $('.progress-bar-inner')))) : $('.category-description-container', {}, @@ -310,12 +312,15 @@ export class GettingStartedPage extends EditorPane { $('.category-description.description', { 'aria-label': category.description + ' ' + localize('pressEnterToSelect', "Press Enter to Select") }, category.description)); return $('button.getting-started-category', - { 'x-dispatch': 'selectCategory:' + category.id, }, + { + 'x-dispatch': 'selectCategory:' + category.id, + 'role': 'listitem', + }, $(ThemeIcon.asCSSSelector(category.icon), {}), categoryDescriptionElement); }); const categoryScrollContainer = $('.getting-started-categories-scrolling-container'); - const categoriesContainer = $('.getting-started-categories-container'); + const categoriesContainer = $('.getting-started-categories-container', { 'role': 'list' }); categoryElements.forEach(element => { categoriesContainer.appendChild(element); }); @@ -384,6 +389,10 @@ export class GettingStartedPage extends EditorPane { const message = assertIsDefined(element.firstChild); const bar = assertIsDefined(element.querySelector('.progress-bar-inner')) as HTMLDivElement; + bar.setAttribute('aria-valuemin', '0'); + bar.setAttribute('aria-valuenow', '' + numDone); + bar.setAttribute('aria-valuemax', '' + numTotal); + bar.style.width = `${(numDone / numTotal) * 100}%`; if (numTotal === numDone) { @@ -429,6 +438,7 @@ export class GettingStartedPage extends EditorPane { 'x-dispatch': 'selectTask:' + task.id, 'data-task-id': task.id, 'aria-expanded': 'false', + 'role': 'listitem', }, $('.codicon' + (task.done ? '.complete.codicon-pass-filled' : '.codicon-circle-large-outline'), { 'data-done-task-id': task.id }), $('.task-description-container', {}, @@ -451,7 +461,7 @@ export class GettingStartedPage extends EditorPane { )) ))); - const detailContainer = $('.getting-started-detail-container'); + const detailContainer = $('.getting-started-detail-container', { 'role': 'list' }); if (this.detailsScrollbar) { this.detailsScrollbar.getDomNode().remove(); this.detailsScrollbar.dispose(); } this.detailsScrollbar = this._register(new DomScrollableElement(detailContainer, { className: 'full-height-scrollable' })); categoryElements.forEach(element => detailContainer.appendChild(element)); From 653f025dfdb664ecee854454c472e4db6b36781e Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 12 Feb 2021 12:08:57 -0800 Subject: [PATCH 092/325] Enable ts check for service-worker Fixes #116533 --- .../webview/browser/pre/service-worker.js | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/contrib/webview/browser/pre/service-worker.js b/src/vs/workbench/contrib/webview/browser/pre/service-worker.js index 1030c047421..f6c93682fea 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/service-worker.js +++ b/src/vs/workbench/contrib/webview/browser/pre/service-worker.js @@ -2,13 +2,18 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +// @ts-check + +/// /// +const sw = /** @type {ServiceWorkerGlobalScope} */ (/** @type {any} */ (self)); + const VERSION = 1; const resourceCacheName = `vscode-resource-cache-${VERSION}`; -const rootPath = self.location.pathname.replace(/\/service-worker.js$/, ''); +const rootPath = sw.location.pathname.replace(/\/service-worker.js$/, ''); /** * Root path for resources @@ -101,11 +106,12 @@ const localhostRequestStore = new RequestStore(); const notFound = () => new Response('Not Found', { status: 404, }); -self.addEventListener('message', async (event) => { +sw.addEventListener('message', async (event) => { switch (event.data.channel) { case 'version': { - self.clients.get(event.source.id).then(client => { + const source = /** @type {Client} */ (event.source); + sw.clients.get(source.id).then(client => { if (client) { client.postMessage({ channel: 'version', @@ -153,26 +159,26 @@ self.addEventListener('message', async (event) => { console.log('Unknown message'); }); -self.addEventListener('fetch', (event) => { +sw.addEventListener('fetch', (event) => { const requestUrl = new URL(event.request.url); // See if it's a resource request - if (requestUrl.origin === self.origin && requestUrl.pathname.startsWith(resourceRoot + '/')) { + if (requestUrl.origin === sw.origin && requestUrl.pathname.startsWith(resourceRoot + '/')) { return event.respondWith(processResourceRequest(event, requestUrl)); } // See if it's a localhost request - if (requestUrl.origin !== self.origin && requestUrl.host.match(/^localhost:(\d+)$/)) { + if (requestUrl.origin !== sw.origin && requestUrl.host.match(/^localhost:(\d+)$/)) { return event.respondWith(processLocalhostRequest(event, requestUrl)); } }); -self.addEventListener('install', (event) => { - event.waitUntil(self.skipWaiting()); // Activate worker immediately +sw.addEventListener('install', (event) => { + event.waitUntil(sw.skipWaiting()); // Activate worker immediately }); -self.addEventListener('activate', (event) => { - event.waitUntil(self.clients.claim()); // Become available to all pages +sw.addEventListener('activate', (event) => { + event.waitUntil(sw.clients.claim()); // Become available to all pages }); /** @@ -180,7 +186,7 @@ self.addEventListener('activate', (event) => { * @param {URL} requestUrl */ async function processResourceRequest(event, requestUrl) { - const client = await self.clients.get(event.clientId); + const client = await sw.clients.get(event.clientId); if (!client) { console.log('Could not find inner client for request'); return notFound(); @@ -252,7 +258,7 @@ async function processResourceRequest(event, requestUrl) { * @param {URL} requestUrl */ async function processLocalhostRequest(event, requestUrl) { - const client = await self.clients.get(event.clientId); + const client = await sw.clients.get(event.clientId); if (!client) { // This is expected when requesting resources on other localhost ports // that are not spawned by vs code @@ -299,7 +305,7 @@ function getWebviewIdForClient(client) { } async function getOuterIframeClient(webviewId) { - const allClients = await self.clients.matchAll({ includeUncontrolled: true }); + const allClients = await sw.clients.matchAll({ includeUncontrolled: true }); return allClients.find(client => { const clientUrl = new URL(client.url); return (clientUrl.pathname === `${rootPath}/` || clientUrl.pathname === `${rootPath}/index.html`) && clientUrl.search.match(new RegExp('\\bid=' + webviewId)); From 7661c8e35cfed8fddf98adf8191659b0f0f88b0e Mon Sep 17 00:00:00 2001 From: Raymond Zhao Date: Fri, 12 Feb 2021 20:10:52 +0000 Subject: [PATCH 093/325] Move emmet to emmetio/emmet npm dependency, fixes #110697 --- extensions/emmet/package.json | 5 ++--- extensions/emmet/yarn.lock | 33 +++++++++++++++++---------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/extensions/emmet/package.json b/extensions/emmet/package.json index c786c715cde..dea1a8fae08 100644 --- a/extensions/emmet/package.json +++ b/extensions/emmet/package.json @@ -430,8 +430,7 @@ "deps": "yarn add vscode-emmet-helper" }, "devDependencies": { - "@types/node": "^12.19.9", - "emmet": "https://github.com/rzhao271/emmet.git#1b2df677d8925ef5ea6da9df8845968403979a0a" + "@types/node": "^12.19.9" }, "dependencies": { "@emmetio/abbreviation": "^2.2.0", @@ -439,7 +438,7 @@ "@emmetio/html-matcher": "^0.3.3", "@emmetio/math-expression": "^1.0.4", "image-size": "^0.5.2", - "vscode-emmet-helper": "2.2.4", + "vscode-emmet-helper": "^2.3.0", "vscode-languageserver-textdocument": "^1.0.1" } } diff --git a/extensions/emmet/yarn.lock b/extensions/emmet/yarn.lock index bebce02cf48..e9ac076c3f0 100644 --- a/extensions/emmet/yarn.lock +++ b/extensions/emmet/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@emmetio/abbreviation@^2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@emmetio/abbreviation/-/abbreviation-2.2.0.tgz#9f8dedbdb00e3136d6d37c6415375c82c0bb477f" - integrity sha512-NPGVUmnr7cLj4i6MKS4c8NjuoIIJROrruJl/8nXsp2MdbDRHvtfq25foySvv/NbfqTQm+P9JzVLDD9JxGIpvkQ== +"@emmetio/abbreviation@^2.2.0", "@emmetio/abbreviation@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@emmetio/abbreviation/-/abbreviation-2.2.1.tgz#d9458fe1f09fe042f019c48aa681165ba613a48d" + integrity sha512-uUNwNgbH0JPlrdXhy8VQbNPLLG7abMvOaLVMblx22i68Rl9r+2N235ALgIYFUty1yXC9DkVw6xMbz/D4QVARcQ== dependencies: "@emmetio/scanner" "^1.0.0" @@ -54,15 +54,16 @@ integrity sha1-Rs/+oRmgoAMxKiHC2bVijLX81EI= "@types/node@^12.19.9": - version "12.19.15" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.15.tgz#0de7e978fb43db62da369db18ea088a63673c182" - integrity sha512-lowukE3GUI+VSYSu6VcBXl14d61Rp5hA1D+61r16qnwC0lYNSqdxcvRh0pswejorHfS+HgwBasM8jLXz0/aOsw== + version "12.20.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.0.tgz#692dfdecd6c97f5380c42dd50f19261f9f604deb" + integrity sha512-0/41wHcurotvSOTHQUFkgL702c3pyWR1mToSrrX3pGPvGfpHTv3Ksx0M4UVuU5VJfjVb62Eyr1eKO1tWNUCg2Q== -"emmet@https://github.com/rzhao271/emmet.git#1b2df677d8925ef5ea6da9df8845968403979a0a": - version "2.3.0" - resolved "https://github.com/rzhao271/emmet.git#1b2df677d8925ef5ea6da9df8845968403979a0a" +emmet@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/emmet/-/emmet-2.3.1.tgz#77614d949d1d01e5c248d08043a13a7f4d539e47" + integrity sha512-u8h++9u3y9QWhn0imUXfQO+s80To5MGD97zd/00wGC39CfNGBPe//ZKepJz9I1LQ2FDRXHrn+e3JaN/53Y5z6A== dependencies: - "@emmetio/abbreviation" "^2.2.0" + "@emmetio/abbreviation" "^2.2.1" "@emmetio/css-abbreviation" "^2.1.2" image-size@^0.5.2: @@ -75,12 +76,12 @@ jsonc-parser@^2.3.0: resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.3.1.tgz#59549150b133f2efacca48fe9ce1ec0659af2342" integrity sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg== -vscode-emmet-helper@2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-2.2.4.tgz#8ab86d2b7fe9e6270b4c77c9fd8d1eb8f3f4c401" - integrity sha512-1N6bMzP1ZzkDGzamvsKxQ/lOmBc4+OQdj0dA2C9A5PSeYV9gh5xbJ061sm+VyFHOGZE+VyUQq5m/WFmFsLbKnA== +vscode-emmet-helper@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-2.3.0.tgz#a98357ad5ac9c71d7c00396f22b7963b1a74cc5c" + integrity sha512-QhU8+HlynMuUkqBYgA3wIDTSsUNkw8GWxLR214Hjvwr0lkFZa0CRqW/PzAI1CFREjSrTxJYQvkVnbfatZzKAuA== dependencies: - emmet "https://github.com/rzhao271/emmet.git#1b2df677d8925ef5ea6da9df8845968403979a0a" + emmet "^2.3.0" jsonc-parser "^2.3.0" vscode-languageserver-textdocument "^1.0.1" vscode-languageserver-types "^3.15.1" From 66d300b1bb74dcb2b17416b6e5e8c991b2f43eb9 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 12:22:34 -0800 Subject: [PATCH 094/325] Enable 3 tests --- .../src/singlefolder-tests/terminal.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index ee31b49cca5..c870811f45e 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -36,7 +36,7 @@ import { assertNoRpc } from '../utils'; disposables.length = 0; }); - test.skip('sendText immediately after createTerminal should not throw', async () => { + test('sendText immediately after createTerminal should not throw', async () => { const terminal = window.createTerminal(); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -57,7 +57,7 @@ import { assertNoRpc } from '../utils'; }); }); - (process.platform === 'linux' ? test.skip : test.skip)('echo works in the default shell', (done) => { + (process.platform === 'linux' ? test.skip : test)('echo works in the default shell', (done) => { disposables.push(window.onDidOpenTerminal(term => { try { equal(terminal, term); @@ -102,7 +102,7 @@ import { assertNoRpc } from '../utils'; }); }); - test.skip('onDidCloseTerminal event fires when terminal is disposed', async () => { + test('onDidCloseTerminal event fires when terminal is disposed', async () => { const terminal = window.createTerminal(); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { From 1170b3158e38b516f78514ec7b4e8a288bd69a37 Mon Sep 17 00:00:00 2001 From: Jean Pierre Date: Fri, 12 Feb 2021 15:54:57 -0500 Subject: [PATCH 095/325] Emmet: add output.reverseAttributes option (#116088) Fixes #110251 --- extensions/emmet/package.json | 5 +++++ extensions/emmet/package.nls.json | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/extensions/emmet/package.json b/extensions/emmet/package.json index dea1a8fae08..0766cda7bc4 100644 --- a/extensions/emmet/package.json +++ b/extensions/emmet/package.json @@ -212,6 +212,11 @@ "type": "number", "default": 0.3, "description": "%emmetPreferencesCssFuzzySearchMinScore%" + }, + "output.reverseAttributes": { + "type": "boolean", + "default": false, + "description": "%emmetPreferencesOutputReverseAttributes%" } } }, diff --git a/extensions/emmet/package.nls.json b/extensions/emmet/package.nls.json index 2a1add8935e..8e168ec4c4e 100644 --- a/extensions/emmet/package.nls.json +++ b/extensions/emmet/package.nls.json @@ -55,5 +55,6 @@ "emmetPreferencesCssOProperties": "Comma separated CSS properties that get the 'o' vendor prefix when used in Emmet abbreviation that starts with `-`. Set to empty string to always avoid the 'o' prefix.", "emmetPreferencesCssMsProperties": "Comma separated CSS properties that get the 'ms' vendor prefix when used in Emmet abbreviation that starts with `-`. Set to empty string to always avoid the 'ms' prefix.", "emmetPreferencesCssFuzzySearchMinScore": "The minimum score (from 0 to 1) that fuzzy-matched abbreviation should achieve. Lower values may produce many false-positive matches, higher values may reduce possible matches.", - "emmetOptimizeStylesheetParsing": "When set to `false`, the whole file is parsed to determine if current position is valid for expanding Emmet abbreviations. When set to `true`, only the content around the current position in css/scss/less files is parsed." + "emmetOptimizeStylesheetParsing": "When set to `false`, the whole file is parsed to determine if current position is valid for expanding Emmet abbreviations. When set to `true`, only the content around the current position in css/scss/less files is parsed.", + "emmetPreferencesOutputReverseAttributes": "If `true`, reverses attribute merging directions when resolving snippets." } From 68f1497536af07831ce150b1b695fe51fdb70b74 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 13:40:59 -0800 Subject: [PATCH 096/325] Skip echo works in the default shell test --- .../vscode-api-tests/src/singlefolder-tests/terminal.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index c870811f45e..71f1008dff7 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -57,7 +57,7 @@ import { assertNoRpc } from '../utils'; }); }); - (process.platform === 'linux' ? test.skip : test)('echo works in the default shell', (done) => { + (process.platform === 'linux' ? test.skip : test.skip)('echo works in the default shell', (done) => { disposables.push(window.onDidOpenTerminal(term => { try { equal(terminal, term); From a5994556a8e57720238ebc79034c020c369c0d6f Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 14:10:21 -0800 Subject: [PATCH 097/325] Re-enable most tests --- .../src/singlefolder-tests/terminal.test.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index 71f1008dff7..aaaeebd859b 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -122,7 +122,7 @@ import { assertNoRpc } from '../utils'; }); }); - test.skip('processId immediately after createTerminal should fetch the pid', async () => { + test('processId immediately after createTerminal should fetch the pid', async () => { const terminal = window.createTerminal(); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -144,7 +144,7 @@ import { assertNoRpc } from '../utils'; }); }); - test.skip('name in constructor should set terminal.name', async () => { + test('name in constructor should set terminal.name', async () => { const terminal = window.createTerminal('a'); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -164,7 +164,7 @@ import { assertNoRpc } from '../utils'; }); }); - test.skip('creationOptions should be set and readonly for TerminalOptions terminals', async () => { + test('creationOptions should be set and readonly for TerminalOptions terminals', async () => { const options = { name: 'foo', hideFromUser: true @@ -190,7 +190,7 @@ import { assertNoRpc } from '../utils'; throws(() => terminalOptions.name = 'bad', 'creationOptions should be readonly at runtime'); }); - test.skip('onDidOpenTerminal should fire when a terminal is created', async () => { + test('onDidOpenTerminal should fire when a terminal is created', async () => { const terminal = window.createTerminal('b'); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -210,7 +210,7 @@ import { assertNoRpc } from '../utils'; }); }); - test.skip('exitStatus.code should be set to undefined after a terminal is disposed', async () => { + test('exitStatus.code should be set to undefined after a terminal is disposed', async () => { const terminal = window.createTerminal(); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -301,7 +301,7 @@ import { assertNoRpc } from '../utils'; // terminal1.show(); // }); - suite.skip('hideFromUser', () => { + suite('hideFromUser', () => { test('should be available to terminals API', async () => { const terminal = window.createTerminal({ name: 'bg', hideFromUser: true }); const result = await new Promise(r => { From 53c2e1b23c77d850ab4109c7bfcf201909fe294c Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 12 Feb 2021 10:11:14 -0800 Subject: [PATCH 098/325] testing: close peek view when associate test state changes Fixes https://github.com/microsoft/vscode/issues/115003 --- .../hierarchalByLocation.ts | 10 +-- .../testing/browser/testingDecorations.ts | 6 +- .../testing/browser/testingExplorerView.ts | 2 +- .../testing/browser/testingOutputPeek.ts | 41 ++++++++++- .../testing/common/testResultService.ts | 70 ++++++++++--------- .../contrib/testing/common/testingAutoRun.ts | 13 ++-- .../testing/common/testingContentProvider.ts | 2 +- .../contrib/testing/common/testingUri.ts | 14 ++-- .../test/common/testResultService.test.ts | 35 ++++++---- .../testing/test/common/testingUri.test.ts | 6 +- 10 files changed, 127 insertions(+), 72 deletions(-) diff --git a/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation.ts b/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation.ts index d785bf0de24..98d7a14b0dc 100644 --- a/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation.ts +++ b/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation.ts @@ -81,12 +81,12 @@ export class HierarchicalByLocationProjection extends Disposable implements ITes // when test states change, reflect in the tree // todo: optimize this to avoid needing to iterate - this._register(results.onTestChanged(([, { item, state, retired, computedState }]) => { + this._register(results.onTestChanged(({ result }) => { for (const i of this.items.values()) { - if (i.test.item.extId === item.extId) { - i.ownState = state.state; - i.retired = retired; - refreshComputedState(computedStateAccessor, i, this.addUpdated, computedState); + if (i.test.item.extId === result.item.extId) { + i.ownState = result.state.state; + i.retired = result.retired; + refreshComputedState(computedStateAccessor, i, this.addUpdated, result.computedState); this.addUpdated(i); this.updateEmitter.fire(); return; diff --git a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts index 01d809934ca..0bb37457281 100644 --- a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts +++ b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts @@ -63,8 +63,8 @@ export class TestingDecorations extends Disposable implements IEditorContributio } this.collection.value = this.testService.subscribeToDiffs(ExtHostTestingResource.TextDocument, uri, () => this.setDecorations(uri)); - this._register(this.results.onTestChanged(([, changed]) => { - if (changed.item.location?.uri.toString() === uri.toString()) { + this._register(this.results.onTestChanged(({ result }) => { + if (result.item.location?.uri.toString() === uri.toString()) { this.setDecorations(uri); } })); @@ -102,7 +102,7 @@ export class TestingDecorations extends Disposable implements IEditorContributio type: TestUriType.ResultActualOutput, messageIndex: i, resultId: result.id, - testId: stateItem.item.extId, + testExtId: stateItem.item.extId, }); newDecorations.push(this.instantiationService.createInstance(TestMessageDecoration, m, uri, m.location, this.editor)); diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts index b1a3c35be43..b9792a16dc4 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts @@ -411,7 +411,7 @@ export class TestingExplorerViewModel extends Disposable { type: TestUriType.ResultMessage, messageIndex: index, resultId: result.id, - testId: item.test!.item.extId, + testExtId: item.test!.item.extId, })); return true; diff --git a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts index 081c8893ad9..89361e1f09d 100644 --- a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts +++ b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts @@ -30,7 +30,7 @@ import { Testing } from 'vs/workbench/contrib/testing/common/constants'; import { ITestItem, ITestMessage, ITestState } from 'vs/workbench/contrib/testing/common/testCollection'; import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys'; import { buildTestUri, parseTestUri, TestUriType } from 'vs/workbench/contrib/testing/common/testingUri'; -import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService'; +import { ITestResultService, TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResultService'; interface ITestDto { test: ITestItem, @@ -71,6 +71,18 @@ export class TestingOutputPeekController extends Disposable implements IEditorCo super(); this.visible = TestingContextKeys.isPeekVisible.bindTo(contextKeyService); this._register(editor.onDidChangeModel(() => this.peek.clear())); + this._register(testResults.onTestChanged((evt) => { + // if the test we're currently showing has its state change to something + // else, then clear the peek + if (evt.reason !== TestResultItemChangeReason.OwnStateChange || evt.previous.state === evt.result.state.state) { + return; + } + + const displayed = this.peek.value?.currentTest(); + if (displayed?.extId === evt.result.item.extId) { + this.peek.clear(); + } + })); } /** @@ -113,13 +125,13 @@ export class TestingOutputPeekController extends Disposable implements IEditorCo this.peek.clear(); } - private async retrieveTest(uri: URI): Promise { + private retrieveTest(uri: URI): ITestDto | undefined { const parts = parseTestUri(uri); if (!parts) { return undefined; } - const test = this.testResults.getResult(parts.resultId)?.getStateByExtId(parts.testId); + const test = this.testResults.getResult(parts.resultId)?.getStateByExtId(parts.testExtId); return test && { test: test.item, state: test.state, @@ -168,6 +180,11 @@ abstract class TestingOutputPeek extends PeekViewWidget { */ public abstract setModel(dto: ITestDto): Promise; + /** + * Returns the test whose data is currently shown in the peek view. + */ + public abstract currentTest(): ITestItem | undefined; + /** * @override */ @@ -205,6 +222,7 @@ const diffEditorOptions: IDiffEditorOptions = { class TestingDiffOutputPeek extends TestingOutputPeek { private readonly diff = this._disposables.add(new MutableDisposable()); + private test: ITestItem | undefined; /** * @override @@ -227,6 +245,7 @@ class TestingDiffOutputPeek extends TestingOutputPeek { return; } + this.test = test; this.show(message.location.range, hintDiffPeekHeight(message)); this.setTitle(message.message.toString(), test.label); @@ -243,6 +262,13 @@ class TestingDiffOutputPeek extends TestingOutputPeek { } } + /** + * @override + */ + public currentTest() { + return this.test; + } + /** * @override */ @@ -254,6 +280,7 @@ class TestingDiffOutputPeek extends TestingOutputPeek { class TestingMessageOutputPeek extends TestingOutputPeek { private readonly preview = this._disposables.add(new MutableDisposable()); + private test: ITestItem | undefined; /** * @override @@ -276,6 +303,7 @@ class TestingMessageOutputPeek extends TestingOutputPeek { return; } + this.test = test; this.show(message.location.range, hintPeekStrHeight(message.message.toString())); this.setTitle(message.message.toString(), test.label); @@ -287,6 +315,13 @@ class TestingMessageOutputPeek extends TestingOutputPeek { } } + /** + * @override + */ + public currentTest() { + return this.test; + } + /** * @override */ diff --git a/src/vs/workbench/contrib/testing/common/testResultService.ts b/src/vs/workbench/contrib/testing/common/testResultService.ts index a0262052764..5ce95376f8b 100644 --- a/src/vs/workbench/contrib/testing/common/testResultService.ts +++ b/src/vs/workbench/contrib/testing/common/testResultService.ts @@ -22,6 +22,18 @@ import { IMainThreadTestCollection } from 'vs/workbench/contrib/testing/common/t */ export type TestStateCount = { [K in TestRunState]: number }; +export const enum TestResultItemChangeReason { + Retired, + ParentRetired, + ComputedStateChange, + OwnStateChange, +} + +export type TestResultItemChange = { result: TestResultItem; } & ( + | { reason: TestResultItemChangeReason.Retired | TestResultItemChangeReason.ParentRetired | TestResultItemChangeReason.ComputedStateChange } + | { reason: TestResultItemChangeReason.OwnStateChange; previous: ITestState } +); + export interface ITestResult { /** * Count of the number of tests in each run state. @@ -188,11 +200,9 @@ export class LiveTestResult implements ITestResult { } private readonly completeEmitter = new Emitter(); - private readonly retireEmitter = new Emitter(); - private readonly changeEmitter = new Emitter(); + private readonly changeEmitter = new Emitter(); private _complete = false; - public readonly onRetired = this.retireEmitter.event; public readonly onChange = this.changeEmitter.event; public readonly onComplete = this.completeEmitter.event; @@ -272,10 +282,7 @@ export class LiveTestResult implements ITestResult { public setAllToState(state: ITestState, when: (_t: TestResultItem) => boolean) { for (const test of this.testByInternalId.values()) { if (when(test)) { - this.counts[test.state.state]--; - test.state = state; - this.counts[state.state]++; - refreshComputedState(this.computedStateAccessor, test, t => this.changeEmitter.fire(t)); + this.fireUpdateAndRefresh(test, state); } } } @@ -292,15 +299,22 @@ export class LiveTestResult implements ITestResult { return; } - if (state.state === entry.state.state) { - entry.state = state; - this.changeEmitter.fire(entry); - } else { - this.counts[entry.state.state]--; - entry.state = state; - this.counts[entry.state.state]++; - refreshComputedState(this.computedStateAccessor, entry, t => this.changeEmitter.fire(t)); + this.fireUpdateAndRefresh(entry, state); + } + + private fireUpdateAndRefresh(entry: TestResultItem, newState: ITestState) { + const previous = entry.state; + entry.state = newState; + + if (newState.state !== previous.state) { + this.counts[previous.state]--; + this.counts[newState.state]++; + refreshComputedState(this.computedStateAccessor, entry, t => ( + t !== entry && this.changeEmitter.fire({ result: t, reason: TestResultItemChangeReason.ComputedStateChange }) + )); } + + this.changeEmitter.fire({ result: entry, reason: TestResultItemChangeReason.OwnStateChange, previous }); } /** @@ -312,7 +326,6 @@ export class LiveTestResult implements ITestResult { return; } - this.retireEmitter.fire(root); const queue: Iterable[] = [[root.id]]; while (queue.length) { for (const id of queue.pop()!) { @@ -320,7 +333,12 @@ export class LiveTestResult implements ITestResult { if (entry && !entry.retired) { entry.retired = true; queue.push(entry.children); - this.changeEmitter.fire(entry); + this.changeEmitter.fire({ + result: entry, + reason: entry === root + ? TestResultItemChangeReason.Retired + : TestResultItemChangeReason.ParentRetired + }); } } } @@ -442,12 +460,7 @@ export interface ITestResultService { /** * Fired when a test changed it state, or its computed state is updated. */ - readonly onTestChanged: Event<[results: ITestResult, item: TestResultItem]>; - - /** - * Fired when a test is retired, in addition to `onTestChanged`. - */ - readonly onTestRetired: Event; + readonly onTestChanged: Event; /** * List of known test results. @@ -482,8 +495,7 @@ const RETAIN_LAST_RESULTS = 64; export class TestResultService implements ITestResultService { declare _serviceBrand: undefined; private changeResultEmitter = new Emitter(); - private testRetiredEmitter = new Emitter(); - private testChangeEmitter = new Emitter<[results: ITestResult, item: TestResultItem]>(); + private testChangeEmitter = new Emitter(); /** * @inheritdoc @@ -500,11 +512,6 @@ export class TestResultService implements ITestResultService { */ public readonly onTestChanged = this.testChangeEmitter.event; - /** - * @inheritdoc - */ - public readonly onTestRetired = this.testRetiredEmitter.event; - private readonly isRunning: IContextKey; private readonly serializedResults: StoredValue; @@ -545,8 +552,7 @@ export class TestResultService implements ITestResultService { } result.onComplete(() => this.onComplete(result)); - result.onChange(t => this.testChangeEmitter.fire([result, t]), this.testChangeEmitter); - result.onRetired(this.testRetiredEmitter.fire, this.testRetiredEmitter); + result.onChange(this.testChangeEmitter.fire, this.testChangeEmitter); this.isRunning.set(true); this.changeResultEmitter.fire({ started: result }); result.setAllToState(queuedState, () => true); diff --git a/src/vs/workbench/contrib/testing/common/testingAutoRun.ts b/src/vs/workbench/contrib/testing/common/testingAutoRun.ts index 360bbf09c31..33ea8045ba4 100644 --- a/src/vs/workbench/contrib/testing/common/testingAutoRun.ts +++ b/src/vs/workbench/contrib/testing/common/testingAutoRun.ts @@ -13,7 +13,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import { getTestingConfiguration, TestingConfigKeys } from 'vs/workbench/contrib/testing/common/configuration'; import { TestIdWithProvider } from 'vs/workbench/contrib/testing/common/testCollection'; import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys'; -import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService'; +import { ITestResultService, TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResultService'; import { ITestService } from 'vs/workbench/contrib/testing/common/testService'; import { IWorkspaceTestCollectionService } from 'vs/workbench/contrib/testing/common/workspaceTestCollectionService'; @@ -90,10 +90,15 @@ export class TestingAutoRun extends Disposable implements ITestingAutoRun { } }, delay)); - store.add(this.results.onTestRetired(test => { + store.add(this.results.onTestChanged(evt => { + if (evt.reason !== TestResultItemChangeReason.Retired) { + return; + } + + const { extId } = evt.result.item; const workspaceTest = mapFind(workspaceTests.workspaceFolderCollections, - ([, c]) => c.getNodeById(test.id) ?? Iterable.find(c.all, t => t.item.extId === test.item.extId)); - const subject = workspaceTest ?? test; + ([, c]) => c.getNodeById(evt.result.id) ?? Iterable.find(c.all, t => t.item.extId === extId)); + const subject = workspaceTest ?? evt.result; rerunIds.set(subject.id, ({ testId: subject.id, providerId: subject.providerId })); diff --git a/src/vs/workbench/contrib/testing/common/testingContentProvider.ts b/src/vs/workbench/contrib/testing/common/testingContentProvider.ts index c63a507d15f..b3e91103ce4 100644 --- a/src/vs/workbench/contrib/testing/common/testingContentProvider.ts +++ b/src/vs/workbench/contrib/testing/common/testingContentProvider.ts @@ -38,7 +38,7 @@ export class TestingContentProvider implements IWorkbenchContribution, ITextMode return null; } - const test = this.resultService.getResult(parsed.resultId)?.getStateByExtId(parsed.testId); + const test = this.resultService.getResult(parsed.resultId)?.getStateByExtId(parsed.testExtId); if (!test) { return null; diff --git a/src/vs/workbench/contrib/testing/common/testingUri.ts b/src/vs/workbench/contrib/testing/common/testingUri.ts index 5f99df72ba0..9503c99e152 100644 --- a/src/vs/workbench/contrib/testing/common/testingUri.ts +++ b/src/vs/workbench/contrib/testing/common/testingUri.ts @@ -15,7 +15,7 @@ export const enum TestUriType { interface IResultTestUri { resultId: string; - testId: string; + testExtId: string; } interface IResultTestMessageReference extends IResultTestUri { @@ -43,19 +43,20 @@ const enum TestUriParts { export const parseTestUri = (uri: URI): ParsedTestUri | undefined => { const type = uri.authority; - const [locationId, testId, ...request] = uri.path.slice(1).split('/'); + const [locationId, ...request] = uri.path.slice(1).split('/'); if (request[0] === TestUriParts.Messages) { const index = Number(request[1]); const part = request[2]; + const testExtId = uri.query; if (type === TestUriParts.Results) { switch (part) { case TestUriParts.Text: - return { resultId: locationId, testId, messageIndex: index, type: TestUriType.ResultMessage }; + return { resultId: locationId, testExtId, messageIndex: index, type: TestUriType.ResultMessage }; case TestUriParts.ActualOutput: - return { resultId: locationId, testId, messageIndex: index, type: TestUriType.ResultActualOutput }; + return { resultId: locationId, testExtId, messageIndex: index, type: TestUriType.ResultActualOutput }; case TestUriParts.ExpectedOutput: - return { resultId: locationId, testId, messageIndex: index, type: TestUriType.ResultExpectedOutput }; + return { resultId: locationId, testExtId, messageIndex: index, type: TestUriType.ResultExpectedOutput }; } } } @@ -71,7 +72,8 @@ export const buildTestUri = (parsed: ParsedTestUri): URI => { const msgRef = (locationId: string, index: number, ...remaining: string[]) => URI.from({ ...uriParts, - path: ['', locationId, parsed.testId, TestUriParts.Messages, index, ...remaining].join('/'), + query: parsed.testExtId, + path: ['', locationId, TestUriParts.Messages, index, ...remaining].join('/'), }); switch (parsed.type) { diff --git a/src/vs/workbench/contrib/testing/test/common/testResultService.test.ts b/src/vs/workbench/contrib/testing/test/common/testResultService.test.ts index c18dab77484..5e243770b86 100644 --- a/src/vs/workbench/contrib/testing/test/common/testResultService.test.ts +++ b/src/vs/workbench/contrib/testing/test/common/testResultService.test.ts @@ -6,28 +6,28 @@ import * as assert from 'assert'; import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; import { InternalTestItem } from 'vs/workbench/contrib/testing/common/testCollection'; -import { LiveTestResult, makeEmptyCounts, TestResultItem, TestResultService } from 'vs/workbench/contrib/testing/common/testResultService'; +import { LiveTestResult, makeEmptyCounts, TestResultItemChange, TestResultItemChangeReason, TestResultService } from 'vs/workbench/contrib/testing/common/testResultService'; import { ReExportedTestRunState as TestRunState } from 'vs/workbench/contrib/testing/common/testStubs'; import { getInitializedMainTestCollection } from 'vs/workbench/contrib/testing/test/common/ownedTestCollection'; import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices'; suite('Workbench - Test Results Service', () => { const getLabelsIn = (it: Iterable) => [...it].map(t => t.item.label).sort(); + const getChangeSummary = () => [...changed] + .map(c => ({ reason: c.reason, label: c.result.item.label })) + .sort((a, b) => a.label.localeCompare(b.label)); let r: LiveTestResult; - let changed = new Set(); - let retired = new Set(); + let changed = new Set(); setup(() => { changed = new Set(); - retired = new Set(); r = LiveTestResult.from( [getInitializedMainTestCollection()], [{ providerId: 'provider', testId: '1' }] ); r.onChange(e => changed.add(e)); - r.onRetired(e => retired.add(e)); }); suite('LiveTestResult', () => { @@ -38,7 +38,6 @@ suite('Workbench - Test Results Service', () => { test('does not change or retire initially', () => { assert.deepStrictEqual(0, changed.size); - assert.deepStrictEqual(0, retired.size); }); test('initializes with the subtree of requested tests', () => { @@ -61,7 +60,12 @@ suite('Workbench - Test Results Service', () => { }); assert.deepStrictEqual(r.getStateByExtId('root\0a')?.state.state, TestRunState.Queued); - assert.deepStrictEqual(getLabelsIn(changed), ['a', 'aa', 'ab', 'root']); + assert.deepStrictEqual(getChangeSummary(), [ + { label: 'a', reason: TestResultItemChangeReason.OwnStateChange }, + { label: 'aa', reason: TestResultItemChangeReason.OwnStateChange }, + { label: 'ab', reason: TestResultItemChangeReason.OwnStateChange }, + { label: 'root', reason: TestResultItemChangeReason.ComputedStateChange }, + ]); }); test('updateState', () => { @@ -74,20 +78,23 @@ suite('Workbench - Test Results Service', () => { assert.deepStrictEqual(r.getStateByExtId('root\0a')?.state.state, TestRunState.Running); // update computed state: assert.deepStrictEqual(r.getStateByExtId('root')?.computedState, TestRunState.Running); - assert.deepStrictEqual(getLabelsIn(changed), ['a', 'root']); + assert.deepStrictEqual(getChangeSummary(), [ + { label: 'a', reason: TestResultItemChangeReason.OwnStateChange }, + { label: 'root', reason: TestResultItemChangeReason.ComputedStateChange }, + ]); }); test('retire', () => { r.retire('root\0a'); - assert.deepStrictEqual(getLabelsIn(changed), ['a', 'aa', 'ab']); - assert.deepStrictEqual(getLabelsIn(retired), ['a']); + assert.deepStrictEqual(getChangeSummary(), [ + { label: 'a', reason: TestResultItemChangeReason.Retired }, + { label: 'aa', reason: TestResultItemChangeReason.ParentRetired }, + { label: 'ab', reason: TestResultItemChangeReason.ParentRetired }, + ]); - retired.clear(); changed.clear(); - r.retire('root\0a'); - assert.deepStrictEqual(getLabelsIn(changed), []); - assert.deepStrictEqual(getLabelsIn(retired), []); + assert.strictEqual(changed.size, 0); }); test('addTestToRun', () => { diff --git a/src/vs/workbench/contrib/testing/test/common/testingUri.test.ts b/src/vs/workbench/contrib/testing/test/common/testingUri.test.ts index 41d534e5d69..e9c1d60412e 100644 --- a/src/vs/workbench/contrib/testing/test/common/testingUri.test.ts +++ b/src/vs/workbench/contrib/testing/test/common/testingUri.test.ts @@ -9,9 +9,9 @@ import { buildTestUri, ParsedTestUri, parseTestUri, TestUriType } from 'vs/workb suite('Workbench - Testing URIs', () => { test('round trip', () => { const uris: ParsedTestUri[] = [ - { type: TestUriType.ResultActualOutput, messageIndex: 42, resultId: 'r', testId: 't' }, - { type: TestUriType.ResultExpectedOutput, messageIndex: 42, resultId: 'r', testId: 't' }, - { type: TestUriType.ResultMessage, messageIndex: 42, resultId: 'r', testId: 't' }, + { type: TestUriType.ResultActualOutput, messageIndex: 42, resultId: 'r', testExtId: 't' }, + { type: TestUriType.ResultExpectedOutput, messageIndex: 42, resultId: 'r', testExtId: 't' }, + { type: TestUriType.ResultMessage, messageIndex: 42, resultId: 'r', testExtId: 't' }, ]; for (const uri of uris) { From 5c449afc04d2fc758636729d712510e2eea1e3d5 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 12 Feb 2021 12:40:53 -0800 Subject: [PATCH 099/325] testing: automatically open peek view on failures Fixes https://github.com/microsoft/vscode/issues/115769 --- .../hierarchalByLocation.ts | 2 +- .../testing/browser/testing.contribution.ts | 3 +- .../testing/browser/testingDecorations.ts | 2 +- .../testing/browser/testingExplorerView.ts | 36 +---- .../testing/browser/testingOutputPeek.ts | 133 ++++++++++++++++-- .../contrib/testing/common/configuration.ts | 28 +++- .../contrib/testing/common/testCollection.ts | 3 +- .../testing/common/testResultService.ts | 31 ++-- .../contrib/testing/common/testServiceImpl.ts | 2 +- .../contrib/testing/common/testingAutoRun.ts | 8 +- .../test/common/testResultService.test.ts | 10 +- 11 files changed, 187 insertions(+), 71 deletions(-) diff --git a/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation.ts b/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation.ts index 98d7a14b0dc..47cbf47ad77 100644 --- a/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation.ts +++ b/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation.ts @@ -81,7 +81,7 @@ export class HierarchicalByLocationProjection extends Disposable implements ITes // when test states change, reflect in the tree // todo: optimize this to avoid needing to iterate - this._register(results.onTestChanged(({ result }) => { + this._register(results.onTestChanged(({ item: result }) => { for (const i of this.items.values()) { if (i.test.item.extId === result.item.extId) { i.ownState = result.state.state; diff --git a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts index 3cbf194564e..295f2c0fa17 100644 --- a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts +++ b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts @@ -19,7 +19,7 @@ import { testingViewIcon } from 'vs/workbench/contrib/testing/browser/icons'; import { TestingDecorations } from 'vs/workbench/contrib/testing/browser/testingDecorations'; import { ITestExplorerFilterState, TestExplorerFilterState } from 'vs/workbench/contrib/testing/browser/testingExplorerFilter'; import { TestingExplorerView } from 'vs/workbench/contrib/testing/browser/testingExplorerView'; -import { CloseTestPeek, TestingOutputPeekController } from 'vs/workbench/contrib/testing/browser/testingOutputPeek'; +import { CloseTestPeek, ITestingPeekOpener, TestingOutputPeekController, TestingPeekOpener } from 'vs/workbench/contrib/testing/browser/testingOutputPeek'; import { TestingViewPaneContainer } from 'vs/workbench/contrib/testing/browser/testingViewPaneContainer'; import { testingConfiguation } from 'vs/workbench/contrib/testing/common/configuration'; import { Testing } from 'vs/workbench/contrib/testing/common/constants'; @@ -38,6 +38,7 @@ registerSingleton(ITestService, TestService); registerSingleton(ITestResultService, TestResultService); registerSingleton(ITestExplorerFilterState, TestExplorerFilterState); registerSingleton(ITestingAutoRun, TestingAutoRun, true); +registerSingleton(ITestingPeekOpener, TestingPeekOpener); registerSingleton(IWorkspaceTestCollectionService, WorkspaceTestCollectionService); const viewContainer = Registry.as(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer({ diff --git a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts index 0bb37457281..341c7b70818 100644 --- a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts +++ b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts @@ -63,7 +63,7 @@ export class TestingDecorations extends Disposable implements IEditorContributio } this.collection.value = this.testService.subscribeToDiffs(ExtHostTestingResource.TextDocument, uri, () => this.setDecorations(uri)); - this._register(this.results.onTestChanged(({ result }) => { + this._register(this.results.onTestChanged(({ item: result }) => { if (result.item.location?.uri.toString() === uri.toString()) { this.setDecorations(uri); } diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts index b9792a16dc4..444e96c7b1c 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts @@ -50,11 +50,10 @@ import { HierarchicalByLocationProjection } from 'vs/workbench/contrib/testing/b import { HierarchicalByNameProjection } from 'vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByName'; import { testingStatesToIcons } from 'vs/workbench/contrib/testing/browser/icons'; import { ITestExplorerFilterState, TestExplorerFilterState, TestingExplorerFilter } from 'vs/workbench/contrib/testing/browser/testingExplorerFilter'; -import { TestingOutputPeekController } from 'vs/workbench/contrib/testing/browser/testingOutputPeek'; +import { ITestingPeekOpener, TestingOutputPeekController } from 'vs/workbench/contrib/testing/browser/testingOutputPeek'; import { TestExplorerViewMode, TestExplorerViewSorting, Testing, testStateNames } from 'vs/workbench/contrib/testing/common/constants'; import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys'; import { cmpPriority, isFailedState } from 'vs/workbench/contrib/testing/common/testingStates'; -import { buildTestUri, TestUriType } from 'vs/workbench/contrib/testing/common/testingUri'; import { ITestResultService, sumCounts, TestStateCount } from 'vs/workbench/contrib/testing/common/testResultService'; import { ITestService } from 'vs/workbench/contrib/testing/common/testService'; import { IWorkspaceTestCollectionService, TestSubscriptionListener } from 'vs/workbench/contrib/testing/common/workspaceTestCollectionService'; @@ -230,6 +229,7 @@ export class TestingExplorerViewModel extends Disposable { @IStorageService private readonly storageService: IStorageService, @IContextKeyService private readonly contextKeyService: IContextKeyService, @ITestResultService private readonly testResults: ITestResultService, + @ITestingPeekOpener private readonly peekOpener: ITestingPeekOpener, ) { super(); @@ -386,35 +386,9 @@ export class TestingExplorerViewModel extends Disposable { */ private async tryPeekError(item: ITestTreeElement) { const lookup = item.test && this.testResults.getStateByExtId(item.test.item.extId); - if (!lookup || !isFailedState(lookup[1].state.state)) { - return false; - } - - const [result, test] = lookup; - const index = test.state.messages.findIndex(m => !!m.location); - if (index === -1) { - return; - } - - const message = test.state.messages[index]; - const pane = await this.editorService.openEditor({ - resource: message.location!.uri, - options: { selection: message.location!.range, preserveFocus: true } - }); - - const control = pane?.getControl(); - if (!isCodeEditor(control)) { - return false; - } - - TestingOutputPeekController.get(control).show(buildTestUri({ - type: TestUriType.ResultMessage, - messageIndex: index, - resultId: result.id, - testExtId: item.test!.item.extId, - })); - - return true; + return lookup && isFailedState(lookup[1].state.state) + ? this.peekOpener.tryPeekFirstError(lookup[0], lookup[1], { preserveFocus: true }) + : false; } private updatePreferredProjection() { diff --git a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts index 89361e1f09d..3ee275e166a 100644 --- a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts +++ b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts @@ -11,7 +11,7 @@ import { Disposable, IReference, MutableDisposable } from 'vs/base/common/lifecy import { clamp } from 'vs/base/common/numbers'; import { count } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; -import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { ICodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction2 } from 'vs/editor/browser/editorExtensions'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { EmbeddedCodeEditorWidget, EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; @@ -20,17 +20,22 @@ import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { IResolvedTextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService'; import { getOuterEditor, IPeekViewService, peekViewTitleBackground, peekViewTitleForeground, peekViewTitleInfoForeground, PeekViewWidget } from 'vs/editor/contrib/peekView/peekView'; import { localize } from 'vs/nls'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ContextKeyExpr, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; +import { createDecorator, IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService'; import { EditorModel } from 'vs/workbench/common/editor'; import { testingPeekBorder } from 'vs/workbench/contrib/testing/browser/theme'; +import { AutoOpenPeekViewWhen, getTestingConfiguration, TestingConfigKeys } from 'vs/workbench/contrib/testing/common/configuration'; import { Testing } from 'vs/workbench/contrib/testing/common/constants'; import { ITestItem, ITestMessage, ITestState } from 'vs/workbench/contrib/testing/common/testCollection'; import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys'; +import { isFailedState } from 'vs/workbench/contrib/testing/common/testingStates'; import { buildTestUri, parseTestUri, TestUriType } from 'vs/workbench/contrib/testing/common/testingUri'; -import { ITestResultService, TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResultService'; +import { ITestResult, ITestResultService, TestResultItem, TestResultItemChange, TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResultService'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; interface ITestDto { test: ITestItem, @@ -41,6 +46,93 @@ interface ITestDto { messageUri: URI; } +export interface ITestingPeekOpener { + _serviceBrand: undefined; + + /** + * Tries to peek the first test error, if the item is in a failed state. + * @returns a boolean indicating whether a peek was opened + */ + tryPeekFirstError(result: ITestResult, test: TestResultItem, options?: Partial): Promise; +} + +export const ITestingPeekOpener = createDecorator('testingPeekOpener'); + +export class TestingPeekOpener extends Disposable implements ITestingPeekOpener { + declare _serviceBrand: undefined; + + constructor( + @IConfigurationService private readonly configuration: IConfigurationService, + @IEditorService private readonly editorService: IEditorService, + @ICodeEditorService private readonly codeEditorService: ICodeEditorService, + @ITestResultService testResults: ITestResultService, + ) { + super(); + this._register(testResults.onTestChanged(this.openPeekOnFailure, this)); + } + + /** + * Tries to peek the first test error, if the item is in a failed state. + * @returns a boolean if a peek was opened + */ + public async tryPeekFirstError(result: ITestResult, test: TestResultItem, options?: Partial) { + const index = test.state.messages.findIndex(m => !!m.location); + if (index === -1) { + return false; + } + + const message = test.state.messages[index]; + const pane = await this.editorService.openEditor({ + resource: message.location!.uri, + options: { selection: message.location!.range, revealIfOpened: true, ...options } + }); + + const control = pane?.getControl(); + if (!isCodeEditor(control)) { + return false; + } + + TestingOutputPeekController.get(control).show(buildTestUri({ + type: TestUriType.ResultMessage, + messageIndex: index, + resultId: result.id, + testExtId: test.item.extId, + })); + + return true; + } + + /** + * Opens the peek view on a test failure, based on user preferences. + */ + private openPeekOnFailure(evt: TestResultItemChange) { + if (!isFailedState(evt.item.state.state) || !evt.item.state.messages.length) { + return; + } + + if (evt.result.isAutoRun && !getTestingConfiguration(this.configuration, TestingConfigKeys.AutoOpenPeekViewDuringAutoRun)) { + return; + } + + const editors = this.codeEditorService.listCodeEditors(); + const cfg = getTestingConfiguration(this.configuration, TestingConfigKeys.AutoOpenPeekView); + + // don't show the peek if the user asked to only auto-open peeks for visible tests, + // and this test is not in any of the editors' models. + const testUri = evt.item.item.location?.uri.toString(); + if (cfg === AutoOpenPeekViewWhen.FailureVisible && (!testUri || !editors.some(e => e.getModel()?.uri.toString() === testUri))) { + return; + } + + const controllers = editors.map(TestingOutputPeekController.get); + if (controllers.some(c => c?.isVisible)) { + return; + } + + this.tryPeekFirstError(evt.result, evt.item); + } +} + /** * Adds output/message peek functionality to code editors. */ @@ -62,6 +154,13 @@ export class TestingOutputPeekController extends Disposable implements IEditorCo */ private readonly visible: IContextKey; + /** + * Gets whether a peek is currently shown in the associated editor. + */ + public get isVisible() { + return this.peek.value; + } + constructor( private readonly editor: ICodeEditor, @IInstantiationService private readonly instantiationService: IInstantiationService, @@ -71,18 +170,7 @@ export class TestingOutputPeekController extends Disposable implements IEditorCo super(); this.visible = TestingContextKeys.isPeekVisible.bindTo(contextKeyService); this._register(editor.onDidChangeModel(() => this.peek.clear())); - this._register(testResults.onTestChanged((evt) => { - // if the test we're currently showing has its state change to something - // else, then clear the peek - if (evt.reason !== TestResultItemChangeReason.OwnStateChange || evt.previous.state === evt.result.state.state) { - return; - } - - const displayed = this.peek.value?.currentTest(); - if (displayed?.extId === evt.result.item.extId) { - this.peek.clear(); - } - })); + this._register(testResults.onTestChanged((evt) => this.closePeekOnTestChange(evt))); } /** @@ -125,6 +213,21 @@ export class TestingOutputPeekController extends Disposable implements IEditorCo this.peek.clear(); } + /** + * If the test we're currently showing has its state change to something + * else, then clear the peek. + */ + private closePeekOnTestChange(evt: TestResultItemChange) { + if (evt.reason !== TestResultItemChangeReason.OwnStateChange || evt.previous.state === evt.item.state.state) { + return; + } + + const displayed = this.peek.value?.currentTest(); + if (displayed?.extId === evt.item.item.extId) { + this.peek.clear(); + } + } + private retrieveTest(uri: URI): ITestDto | undefined { const parts = parseTestUri(uri); if (!parts) { diff --git a/src/vs/workbench/contrib/testing/common/configuration.ts b/src/vs/workbench/contrib/testing/common/configuration.ts index 0630b3f40ac..546ec5ff9da 100644 --- a/src/vs/workbench/contrib/testing/common/configuration.ts +++ b/src/vs/workbench/contrib/testing/common/configuration.ts @@ -8,7 +8,14 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IConfigurationNode } from 'vs/platform/configuration/common/configurationRegistry'; export const enum TestingConfigKeys { - AutoRunDelay = 'testing.autoRun.delay' + AutoRunDelay = 'testing.autoRun.delay', + AutoOpenPeekView = 'testing.automaticallyOpenPeekView', + AutoOpenPeekViewDuringAutoRun = 'testing.automaticallyOpenPeekViewDuringAutoRun', +} + +export const enum AutoOpenPeekViewWhen { + FailureVisible = 'failureInVisibleDocument', + FailureAnywhere = 'failureAnywhere', } export const testingConfiguation: IConfigurationNode = { @@ -23,11 +30,30 @@ export const testingConfiguation: IConfigurationNode = { description: localize('testing.autoRun.delay', "How long to wait, in milliseconds, after a test is marked as outdated and starting a new run."), default: 1000, }, + [TestingConfigKeys.AutoOpenPeekView]: { + description: localize('testing.automaticallyOpenPeekView', "Configures when the error peek view is automatically opened."), + enum: [ + AutoOpenPeekViewWhen.FailureAnywhere, + AutoOpenPeekViewWhen.FailureVisible, + ], + default: AutoOpenPeekViewWhen.FailureVisible, + enumDescriptions: [ + localize('testing.automaticallyOpenPeekView.failureAnywhere', "Open automatically no matter where the failure is."), + localize('testing.automaticallyOpenPeekView.failureInVisibleDocument', "Open automatically when a test fails in a visible document.") + ], + }, + [TestingConfigKeys.AutoOpenPeekViewDuringAutoRun]: { + description: localize('testing.automaticallyOpenPeekViewDuringAutoRun', "Controls whether to automatically open the peek view during auto-run mode."), + type: 'boolean', + default: false, + } } }; export interface ITestingConfiguration { [TestingConfigKeys.AutoRunDelay]: number; + [TestingConfigKeys.AutoOpenPeekView]: AutoOpenPeekViewWhen; + [TestingConfigKeys.AutoOpenPeekViewDuringAutoRun]: boolean; } export const getTestingConfiguration = (config: IConfigurationService, key: K) => config.getValue(key); diff --git a/src/vs/workbench/contrib/testing/common/testCollection.ts b/src/vs/workbench/contrib/testing/common/testCollection.ts index 8ceb490a2dc..b90a86c393e 100644 --- a/src/vs/workbench/contrib/testing/common/testCollection.ts +++ b/src/vs/workbench/contrib/testing/common/testCollection.ts @@ -15,11 +15,12 @@ export interface TestIdWithProvider { } /** - * Request to them main thread to run a set of tests. + * Request to the main thread to run a set of tests. */ export interface RunTestsRequest { tests: TestIdWithProvider[]; debug: boolean; + isAutoRun?: boolean; } /** diff --git a/src/vs/workbench/contrib/testing/common/testResultService.ts b/src/vs/workbench/contrib/testing/common/testResultService.ts index 5ce95376f8b..371d312c767 100644 --- a/src/vs/workbench/contrib/testing/common/testResultService.ts +++ b/src/vs/workbench/contrib/testing/common/testResultService.ts @@ -12,7 +12,7 @@ import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storag import { TestRunState } from 'vs/workbench/api/common/extHostTypes'; import { IComputedStateAccessor, refreshComputedState } from 'vs/workbench/contrib/testing/common/getComputedState'; import { StoredValue } from 'vs/workbench/contrib/testing/common/storedValue'; -import { IncrementalTestCollectionItem, ITestState, TestIdWithProvider } from 'vs/workbench/contrib/testing/common/testCollection'; +import { IncrementalTestCollectionItem, ITestState, RunTestsRequest } from 'vs/workbench/contrib/testing/common/testCollection'; import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys'; import { statesInOrder } from 'vs/workbench/contrib/testing/common/testingStates'; import { IMainThreadTestCollection } from 'vs/workbench/contrib/testing/common/testService'; @@ -29,7 +29,7 @@ export const enum TestResultItemChangeReason { OwnStateChange, } -export type TestResultItemChange = { result: TestResultItem; } & ( +export type TestResultItemChange = { item: TestResultItem; result: ITestResult } & ( | { reason: TestResultItemChangeReason.Retired | TestResultItemChangeReason.ParentRetired | TestResultItemChangeReason.ComputedStateChange } | { reason: TestResultItemChangeReason.OwnStateChange; previous: ITestState } ); @@ -50,6 +50,11 @@ export interface ITestResult { */ readonly isComplete: boolean; + /** + * Whether this test result is triggered from an auto run. + */ + readonly isAutoRun?: boolean; + /** * Gets the state of the test by its extension-assigned ID. */ @@ -180,11 +185,11 @@ export class LiveTestResult implements ITestResult { */ public static from( collections: ReadonlyArray, - tests: ReadonlyArray, + req: RunTestsRequest, ) { const testByExtId = new Map(); const testByInternalId = new Map(); - for (const test of tests) { + for (const test of req.tests) { for (const collection of collections) { const node = collection.getNodeById(test.testId); if (!node) { @@ -196,7 +201,7 @@ export class LiveTestResult implements ITestResult { } } - return new LiveTestResult(collections, testByExtId, testByInternalId); + return new LiveTestResult(collections, testByExtId, testByInternalId, !!req.isAutoRun); } private readonly completeEmitter = new Emitter(); @@ -265,6 +270,7 @@ export class LiveTestResult implements ITestResult { private readonly collections: ReadonlyArray, private readonly testByExtId: Map, private readonly testByInternalId: Map, + public readonly isAutoRun: boolean, ) { this.counts[TestRunState.Unset] = testByInternalId.size; } @@ -310,11 +316,11 @@ export class LiveTestResult implements ITestResult { this.counts[previous.state]--; this.counts[newState.state]++; refreshComputedState(this.computedStateAccessor, entry, t => ( - t !== entry && this.changeEmitter.fire({ result: t, reason: TestResultItemChangeReason.ComputedStateChange }) + t !== entry && this.changeEmitter.fire({ item: t, result: this, reason: TestResultItemChangeReason.ComputedStateChange }) )); } - this.changeEmitter.fire({ result: entry, reason: TestResultItemChangeReason.OwnStateChange, previous }); + this.changeEmitter.fire({ item: entry, result: this, reason: TestResultItemChangeReason.OwnStateChange, previous }); } /** @@ -334,7 +340,8 @@ export class LiveTestResult implements ITestResult { entry.retired = true; queue.push(entry.children); this.changeEmitter.fire({ - result: entry, + result: this, + item: entry, reason: entry === root ? TestResultItemChangeReason.Retired : TestResultItemChangeReason.ParentRetired @@ -523,8 +530,12 @@ export class TestResultService implements ITestResultService { target: StorageTarget.MACHINE }, storage); - for (const value of this.serializedResults.get([])) { - this.results.push(new HydratedTestResult(value)); + try { + for (const value of this.serializedResults.get([])) { + this.results.push(new HydratedTestResult(value)); + } + } catch (e) { + // outdated structure } } diff --git a/src/vs/workbench/contrib/testing/common/testServiceImpl.ts b/src/vs/workbench/contrib/testing/common/testServiceImpl.ts index 58787aa18f2..95d4a9e7bc8 100644 --- a/src/vs/workbench/contrib/testing/common/testServiceImpl.ts +++ b/src/vs/workbench/contrib/testing/common/testServiceImpl.ts @@ -124,7 +124,7 @@ export class TestService extends Disposable implements ITestService { const subscriptions = [...this.testSubscriptions.values()] .filter(v => req.tests.some(t => v.collection.getNodeById(t.testId))) .map(s => this.subscribeToDiffs(s.ident.resource, s.ident.uri)); - const result = this.testResults.push(LiveTestResult.from(subscriptions.map(s => s.object), req.tests)); + const result = this.testResults.push(LiveTestResult.from(subscriptions.map(s => s.object), req)); try { const tests = groupBy(req.tests, (a, b) => a.providerId === b.providerId ? 0 : 1); diff --git a/src/vs/workbench/contrib/testing/common/testingAutoRun.ts b/src/vs/workbench/contrib/testing/common/testingAutoRun.ts index 33ea8045ba4..a1eae07dd53 100644 --- a/src/vs/workbench/contrib/testing/common/testingAutoRun.ts +++ b/src/vs/workbench/contrib/testing/common/testingAutoRun.ts @@ -82,7 +82,7 @@ export class TestingAutoRun extends Disposable implements ITestingAutoRun { isRunning = true; rerunIds.clear(); - await this.testService.runTests({ debug: false, tests }); + await this.testService.runTests({ debug: false, tests, isAutoRun: true }); isRunning = false; if (rerunIds.size > 0) { @@ -95,10 +95,10 @@ export class TestingAutoRun extends Disposable implements ITestingAutoRun { return; } - const { extId } = evt.result.item; + const { extId } = evt.item.item; const workspaceTest = mapFind(workspaceTests.workspaceFolderCollections, - ([, c]) => c.getNodeById(evt.result.id) ?? Iterable.find(c.all, t => t.item.extId === extId)); - const subject = workspaceTest ?? evt.result; + ([, c]) => c.getNodeById(evt.item.id) ?? Iterable.find(c.all, t => t.item.extId === extId)); + const subject = workspaceTest ?? evt.item; rerunIds.set(subject.id, ({ testId: subject.id, providerId: subject.providerId })); diff --git a/src/vs/workbench/contrib/testing/test/common/testResultService.test.ts b/src/vs/workbench/contrib/testing/test/common/testResultService.test.ts index 5e243770b86..86851a62f51 100644 --- a/src/vs/workbench/contrib/testing/test/common/testResultService.test.ts +++ b/src/vs/workbench/contrib/testing/test/common/testResultService.test.ts @@ -14,7 +14,7 @@ import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServic suite('Workbench - Test Results Service', () => { const getLabelsIn = (it: Iterable) => [...it].map(t => t.item.label).sort(); const getChangeSummary = () => [...changed] - .map(c => ({ reason: c.reason, label: c.result.item.label })) + .map(c => ({ reason: c.reason, label: c.item.item.label })) .sort((a, b) => a.label.localeCompare(b.label)); let r: LiveTestResult; @@ -24,7 +24,7 @@ suite('Workbench - Test Results Service', () => { changed = new Set(); r = LiveTestResult.from( [getInitializedMainTestCollection()], - [{ providerId: 'provider', testId: '1' }] + { tests: [{ providerId: 'provider', testId: '1' }], debug: false } ); r.onChange(e => changed.add(e)); @@ -32,7 +32,7 @@ suite('Workbench - Test Results Service', () => { suite('LiveTestResult', () => { test('is empty if no tests are requesteed', () => { - const r = LiveTestResult.from([getInitializedMainTestCollection()], []); + const r = LiveTestResult.from([getInitializedMainTestCollection()], { tests: [], debug: false }); assert.deepStrictEqual(getLabelsIn(r.tests), []); }); @@ -170,7 +170,7 @@ suite('Workbench - Test Results Service', () => { const r2 = results.push(LiveTestResult.from( [getInitializedMainTestCollection()], - [{ providerId: 'provider', testId: '1' }] + { tests: [{ providerId: 'provider', testId: '1' }], debug: false } )); results.clear(); @@ -181,7 +181,7 @@ suite('Workbench - Test Results Service', () => { results.push(r); const r2 = results.push(LiveTestResult.from( [getInitializedMainTestCollection()], - [{ providerId: 'provider', testId: '1' }] + { tests: [{ providerId: 'provider', testId: '1' }], debug: false } )); assert.deepStrictEqual(results.results, [r2, r]); From 6693b29b19cc279578c45f8bda222eec24b7e14e Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 12 Feb 2021 14:17:01 -0800 Subject: [PATCH 100/325] testing: show peek link in hover Fixes https://github.com/microsoft/vscode/issues/115770 --- .../editor/contrib/hover/modesContentHover.ts | 4 ++++ .../testing/browser/testing.contribution.ts | 10 ++++++++++ .../testing/browser/testingDecorations.ts | 17 ++++++++++++----- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/contrib/hover/modesContentHover.ts b/src/vs/editor/contrib/hover/modesContentHover.ts index ee10d9b8003..7b401019e06 100644 --- a/src/vs/editor/contrib/hover/modesContentHover.ts +++ b/src/vs/editor/contrib/hover/modesContentHover.ts @@ -118,6 +118,10 @@ class ModesContentComputer implements IHoverComputer { const maxColumn = model.getLineMaxColumn(lineNumber); const lineDecorations = this._editor.getLineDecorations(lineNumber).filter((d) => { + if (d.options.isWholeLine) { + return true; + } + const startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1; const endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn; if (startColumn > hoverRange.startColumn || hoverRange.endColumn > endColumn) { diff --git a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts index 295f2c0fa17..8a9600b6b63 100644 --- a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts +++ b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts @@ -128,4 +128,14 @@ CommandsRegistry.registerCommand({ } }); +CommandsRegistry.registerCommand({ + id: 'vscode.peekTestError', + handler: async (accessor: ServicesAccessor, extId: string) => { + const lookup = accessor.get(ITestResultService).getStateByExtId(extId); + if (lookup) { + accessor.get(ITestingPeekOpener).tryPeekFirstError(lookup[0], lookup[1]); + } + } +}); + Registry.as(ConfigurationExtensions.Configuration).registerConfiguration(testingConfiguation); diff --git a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts index 341c7b70818..6006946567f 100644 --- a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts +++ b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts @@ -29,7 +29,7 @@ import { TestingOutputPeekController } from 'vs/workbench/contrib/testing/browse import { testMessageSeverityColors } from 'vs/workbench/contrib/testing/browser/theme'; import { IncrementalTestCollectionItem, ITestMessage } from 'vs/workbench/contrib/testing/common/testCollection'; import { buildTestUri, TestUriType } from 'vs/workbench/contrib/testing/common/testingUri'; -import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService'; +import { ITestResultService, TestResultItem } from 'vs/workbench/contrib/testing/common/testResultService'; import { IMainThreadTestCollection, ITestService } from 'vs/workbench/contrib/testing/common/testService'; export class TestingDecorations extends Disposable implements IEditorContribution { @@ -87,7 +87,7 @@ export class TestingDecorations extends Disposable implements IEditorContributio const stateLookup = this.results.getStateByExtId(test.item.extId); if (hasValidLocation(uri, test.item)) { newDecorations.push(this.instantiationService.createInstance( - RunTestDecoration, test, ref.object, test.item.location, this.editor, stateLookup?.[1].computedState)); + RunTestDecoration, test, ref.object, test.item.location, this.editor, stateLookup?.[1])); } if (!stateLookup) { @@ -172,7 +172,7 @@ class RunTestDecoration extends Disposable implements ITestDecoration { private readonly collection: IMainThreadTestCollection, private readonly location: ModeLocation, private readonly editor: ICodeEditor, - computedState: TestRunState | undefined, + stateItem: TestResultItem | undefined, @ITestService private readonly testService: ITestService, @IContextMenuService private readonly contextMenuService: IContextMenuService, @ICommandService private readonly commandService: ICommandService, @@ -180,14 +180,21 @@ class RunTestDecoration extends Disposable implements ITestDecoration { super(); this.line = location.range.startLineNumber; - const icon = computedState !== undefined && computedState !== TestRunState.Unset - ? testingStatesToIcons.get(computedState)! + const icon = stateItem?.computedState !== undefined && stateItem.computedState !== TestRunState.Unset + ? testingStatesToIcons.get(stateItem.computedState)! : test.children.size > 0 ? testingRunAllIcon : testingRunIcon; + const hoverMessage = new MarkdownString('', true).appendText(localize('failedHoverMessage', '{0} has failed. ', test.item.label)); + if (stateItem?.state.messages.length) { + const args = encodeURIComponent(JSON.stringify([test.item.extId])); + hoverMessage.appendMarkdown(`[${localize('failedPeekAction', 'Peek Error')}](command:vscode.peekTestError?${args})`); + } + this.editorDecoration = { range: firstLineRange(this.location.range), options: { isWholeLine: true, + hoverMessage, glyphMarginClassName: ThemeIcon.asClassName(icon) + ' testing-run-glyph', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, glyphMarginHoverMessage: new MarkdownString().appendText(localize('testing.clickToRun', 'Click to run tests, right click for more options')), From 7934b9d439cf450b2f0dd5bc36dc318dde17e272 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 14:55:49 -0800 Subject: [PATCH 101/325] Skip all but 2 --- .../src/singlefolder-tests/terminal.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index aaaeebd859b..ae570bcd7a5 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -164,7 +164,7 @@ import { assertNoRpc } from '../utils'; }); }); - test('creationOptions should be set and readonly for TerminalOptions terminals', async () => { + test.skip('creationOptions should be set and readonly for TerminalOptions terminals', async () => { const options = { name: 'foo', hideFromUser: true @@ -190,7 +190,7 @@ import { assertNoRpc } from '../utils'; throws(() => terminalOptions.name = 'bad', 'creationOptions should be readonly at runtime'); }); - test('onDidOpenTerminal should fire when a terminal is created', async () => { + test.skip('onDidOpenTerminal should fire when a terminal is created', async () => { const terminal = window.createTerminal('b'); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -210,7 +210,7 @@ import { assertNoRpc } from '../utils'; }); }); - test('exitStatus.code should be set to undefined after a terminal is disposed', async () => { + test.skip('exitStatus.code should be set to undefined after a terminal is disposed', async () => { const terminal = window.createTerminal(); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -301,7 +301,7 @@ import { assertNoRpc } from '../utils'; // terminal1.show(); // }); - suite('hideFromUser', () => { + suite.skip('hideFromUser', () => { test('should be available to terminals API', async () => { const terminal = window.createTerminal({ name: 'bg', hideFromUser: true }); const result = await new Promise(r => { From 778ce3d6af25be81e88efe74ec2d88585408e5f2 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Fri, 12 Feb 2021 15:18:31 -0800 Subject: [PATCH 102/325] Add potential top level command entries --- .../common/gettingStartedContent.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/vs/workbench/services/gettingStarted/common/gettingStartedContent.ts b/src/vs/workbench/services/gettingStarted/common/gettingStartedContent.ts index f96301a0577..64e10c2eb92 100644 --- a/src/vs/workbench/services/gettingStarted/common/gettingStartedContent.ts +++ b/src/vs/workbench/services/gettingStarted/common/gettingStartedContent.ts @@ -40,6 +40,26 @@ type GettingStartedCategory = { type GettingStartedContent = GettingStartedCategory[]; export const content: GettingStartedContent = [ + // { + // id: 'topLevelCommandPalette', + // title: localize('gettingStarted.commandPalette.title', "Command Palette"), + // description: localize('gettingStarted.commandPalette.description', "The one keybinding to show you everything VS Code can do."), + // icon: Codicon.symbolColor, + // content: { + // type: 'command', + // command: 'workbench.action.showCommands', + // } + // }, + // { + // id: 'topLevelSeeExtensions', + // title: localize('gettingStarted.languageSupport.title', "Install Language Support"), + // description: localize('gettingStarted.languageSupport.description', "Want even more features? Install extensions to add support for languages like Python, C, or Java."), + // icon: Codicon.extensions, + // content: { + // type: 'command', + // command: 'workbench.extensions.action.showPopularExtensions', + // } + // }, { id: 'Codespaces', title: localize('gettingStarted.codespaces.title', "Primer on Codespaces"), From 0ebe81ecc1e993115f376d8216db9684cf512d4f Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 15:19:34 -0800 Subject: [PATCH 103/325] Revert "Skip all but 2" This reverts commit 7934b9d439cf450b2f0dd5bc36dc318dde17e272. --- .../src/singlefolder-tests/terminal.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index ae570bcd7a5..aaaeebd859b 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -164,7 +164,7 @@ import { assertNoRpc } from '../utils'; }); }); - test.skip('creationOptions should be set and readonly for TerminalOptions terminals', async () => { + test('creationOptions should be set and readonly for TerminalOptions terminals', async () => { const options = { name: 'foo', hideFromUser: true @@ -190,7 +190,7 @@ import { assertNoRpc } from '../utils'; throws(() => terminalOptions.name = 'bad', 'creationOptions should be readonly at runtime'); }); - test.skip('onDidOpenTerminal should fire when a terminal is created', async () => { + test('onDidOpenTerminal should fire when a terminal is created', async () => { const terminal = window.createTerminal('b'); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -210,7 +210,7 @@ import { assertNoRpc } from '../utils'; }); }); - test.skip('exitStatus.code should be set to undefined after a terminal is disposed', async () => { + test('exitStatus.code should be set to undefined after a terminal is disposed', async () => { const terminal = window.createTerminal(); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -301,7 +301,7 @@ import { assertNoRpc } from '../utils'; // terminal1.show(); // }); - suite.skip('hideFromUser', () => { + suite('hideFromUser', () => { test('should be available to terminals API', async () => { const terminal = window.createTerminal({ name: 'bg', hideFromUser: true }); const result = await new Promise(r => { From 0e3ec619b69d742083d2808cc9810b4c4eca53a3 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 15:19:45 -0800 Subject: [PATCH 104/325] Revert "Re-enable most tests" This reverts commit a5994556a8e57720238ebc79034c020c369c0d6f. --- .../src/singlefolder-tests/terminal.test.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index aaaeebd859b..71f1008dff7 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -122,7 +122,7 @@ import { assertNoRpc } from '../utils'; }); }); - test('processId immediately after createTerminal should fetch the pid', async () => { + test.skip('processId immediately after createTerminal should fetch the pid', async () => { const terminal = window.createTerminal(); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -144,7 +144,7 @@ import { assertNoRpc } from '../utils'; }); }); - test('name in constructor should set terminal.name', async () => { + test.skip('name in constructor should set terminal.name', async () => { const terminal = window.createTerminal('a'); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -164,7 +164,7 @@ import { assertNoRpc } from '../utils'; }); }); - test('creationOptions should be set and readonly for TerminalOptions terminals', async () => { + test.skip('creationOptions should be set and readonly for TerminalOptions terminals', async () => { const options = { name: 'foo', hideFromUser: true @@ -190,7 +190,7 @@ import { assertNoRpc } from '../utils'; throws(() => terminalOptions.name = 'bad', 'creationOptions should be readonly at runtime'); }); - test('onDidOpenTerminal should fire when a terminal is created', async () => { + test.skip('onDidOpenTerminal should fire when a terminal is created', async () => { const terminal = window.createTerminal('b'); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -210,7 +210,7 @@ import { assertNoRpc } from '../utils'; }); }); - test('exitStatus.code should be set to undefined after a terminal is disposed', async () => { + test.skip('exitStatus.code should be set to undefined after a terminal is disposed', async () => { const terminal = window.createTerminal(); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -301,7 +301,7 @@ import { assertNoRpc } from '../utils'; // terminal1.show(); // }); - suite('hideFromUser', () => { + suite.skip('hideFromUser', () => { test('should be available to terminals API', async () => { const terminal = window.createTerminal({ name: 'bg', hideFromUser: true }); const result = await new Promise(r => { From 6841c52357dc2141f98a1ffee391fe5708c2876c Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 15:20:17 -0800 Subject: [PATCH 105/325] Try conpty in integration tests --- .../vscode-api-tests/src/singlefolder-tests/terminal.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index 71f1008dff7..48615e433f6 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -19,8 +19,6 @@ import { assertNoRpc } from '../utils'; extensionContext = (global as any).testExtensionContext; const config = workspace.getConfiguration('terminal.integrated'); - // Disable conpty in integration tests because of https://github.com/microsoft/vscode/issues/76548 - await config.update('windowsEnableConpty', false, ConfigurationTarget.Global); // Disable exit alerts as tests may trigger then and we're not testing the notifications await config.update('showExitAlert', false, ConfigurationTarget.Global); // Canvas may cause problems when running in a container From 1b897365d72b42e2d1161227cfbe67c65de0941d Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 15:22:34 -0800 Subject: [PATCH 106/325] Revert "Move ptyService out of shared proc temporarily" This reverts commit 8912ec1803a1e775d66eb51f409ed9a8e374fa5b. --- .../terminal/electron-browser/localPtyService.ts | 1 - src/vs/platform/terminal/node/ptyService.ts | 3 +-- .../electron-sandbox/terminal.contribution.ts | 11 +++-------- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/vs/platform/terminal/electron-browser/localPtyService.ts b/src/vs/platform/terminal/electron-browser/localPtyService.ts index 6e097451205..4944517f2d9 100644 --- a/src/vs/platform/terminal/electron-browser/localPtyService.ts +++ b/src/vs/platform/terminal/electron-browser/localPtyService.ts @@ -110,7 +110,6 @@ export class LocalPtyService extends Disposable implements IPtyService { dispose() { // this._isDisposed = true; - console.log('LocalPtyService.dispose'); super.dispose(); } diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index 17b55d739e5..af4db72adb1 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -31,13 +31,12 @@ export class PtyService extends Disposable implements IPtyService { readonly onProcessResolvedShellLaunchConfig = this._onProcessResolvedShellLaunchConfig.event; constructor( - @ILogService private readonly _logService: ILogService + private readonly _logService: ILogService ) { super(); } dispose() { - console.log('PtyService.dispose'); for (const pty of this._ptys.values()) { pty.shutdown(true); } diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts index 0c9f0ae675c..181c5f37ab6 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts @@ -3,13 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -// import { registerSharedProcessRemoteService } from 'vs/platform/ipc/electron-sandbox/services'; -// import { TerminalIpcChannels } from 'vs/platform/terminal/common/terminal'; +import { registerSharedProcessRemoteService } from 'vs/platform/ipc/electron-sandbox/services'; +import { TerminalIpcChannels } from 'vs/platform/terminal/common/terminal'; import { ILocalPtyService } from 'vs/platform/terminal/electron-sandbox/terminal'; -// eslint-disable-next-line -import { PtyService } from 'vs/platform/terminal/node/ptyService'; -// registerSharedProcessRemoteService(ILocalPtyService, TerminalIpcChannels.LocalPty, { supportsDelayedInstantiation: true }); - -registerSingleton(ILocalPtyService, PtyService, true); +registerSharedProcessRemoteService(ILocalPtyService, TerminalIpcChannels.LocalPty, { supportsDelayedInstantiation: true }); From e9ecaca14fed4b874f7090faba66f99fca893258 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Fri, 12 Feb 2021 15:22:34 -0800 Subject: [PATCH 107/325] Rescan task scroll container after task selection animation complete Fixes #116521 --- .../contrib/welcome/gettingStarted/browser/gettingStarted.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts index d17e7d5c275..f890c8f273e 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts @@ -242,6 +242,11 @@ export class GettingStartedPage extends EditorPane { mediaElement.setAttribute('src', ''); mediaElement.setAttribute('alt', ''); } + setTimeout(() => { + // rescan after animation finishes + this.detailsScrollbar?.scanDomNode(); + this.detailImageScrollbar?.scanDomNode(); + }, 100); this.detailsScrollbar?.scanDomNode(); this.detailImageScrollbar?.scanDomNode(); } From 656c907867ab07f7ed91b10167d9b851570e534b Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 15:22:52 -0800 Subject: [PATCH 108/325] Revert "Register ptyservice in localptyservice" This reverts commit 4713b130e11303cc1c75934cfaaebc69baaebe89. --- src/vs/platform/terminal/electron-browser/localPtyService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/terminal/electron-browser/localPtyService.ts b/src/vs/platform/terminal/electron-browser/localPtyService.ts index 4944517f2d9..d4c19fc86ef 100644 --- a/src/vs/platform/terminal/electron-browser/localPtyService.ts +++ b/src/vs/platform/terminal/electron-browser/localPtyService.ts @@ -97,7 +97,7 @@ export class LocalPtyService extends Disposable implements IPtyService { // })); // Create proxy and forward events - const proxy = this._register(new PtyService(this._logService)); + const proxy = new PtyService(this._logService); // const proxy = ProxyChannel.toService(client.getChannel(TerminalIpcChannels.PtyHost)); this._register(proxy.onProcessData(e => this._onProcessData.fire(e))); this._register(proxy.onProcessExit(e => this._onProcessExit.fire(e))); From 3d9a48e0f5fed23c8c71abe307806e49d5571f70 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 15:23:22 -0800 Subject: [PATCH 109/325] Revert "Bring ptyService into shared proc" This reverts commit dc4fa4878fb75c920046d54f1d96c9b6a6b3c2c6. --- package.json | 2 +- remote/package.json | 2 +- remote/yarn.lock | 8 +- scripts/test-integration.sh | 10 ++- .../electron-browser/localPtyService.ts | 90 +++++++++---------- yarn.lock | 8 +- 6 files changed, 62 insertions(+), 58 deletions(-) diff --git a/package.json b/package.json index b081a2aa694..c6300383bea 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "native-is-elevated": "0.4.1", "native-keymap": "2.2.1", "native-watchdog": "1.3.0", - "node-pty": "0.10.0-beta19", + "node-pty": "0.11.0-beta1", "spdlog": "^0.11.1", "sudo-prompt": "9.1.1", "tas-client-umd": "0.1.2", diff --git a/remote/package.json b/remote/package.json index 3d36902888e..86a8a64cb84 100644 --- a/remote/package.json +++ b/remote/package.json @@ -13,7 +13,7 @@ "jschardet": "2.2.1", "minimist": "^1.2.5", "native-watchdog": "1.3.0", - "node-pty": "0.10.0-beta19", + "node-pty": "0.11.0-beta1", "spdlog": "^0.11.1", "tas-client-umd": "0.1.2", "vscode-nsfw": "1.2.9", diff --git a/remote/yarn.lock b/remote/yarn.lock index a264b79dde8..35efe72cbb4 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -304,10 +304,10 @@ node-addon-api@^3.0.2: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.0.2.tgz#04bc7b83fd845ba785bb6eae25bc857e1ef75681" integrity sha512-+D4s2HCnxPd5PjjI0STKwncjXTUKKqm74MDMz9OPXavjsGmjkvwgLtA5yoxJUdmpj52+2u+RrXgPipahKczMKg== -node-pty@0.10.0-beta19: - version "0.10.0-beta19" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.0-beta19.tgz#b7cbfba53f7b2a816efe8c9302dd083cc5874458" - integrity sha512-4UIOGMvpofUbe+ZniBUtY8zc/psMURSzbMonQgIhK7JlMQsUwcbkDIrKzStVLJX0FkeZpUNlsVtK7qqzHvrUZA== +node-pty@0.11.0-beta1: + version "0.11.0-beta1" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.11.0-beta1.tgz#961cf7ab56e0a689b71a19a46371ea090050f312" + integrity sha512-nHMB0K3LZTqjWv3X11XFdy/L4V2eMEk0RbmbVN02GPOkXdMy2NITI0px/x0JtNeIolRPq6r5hf5NUcNc2LJizw== dependencies: nan "^2.14.0" diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index b1d5e9588e3..610759621b6 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -55,9 +55,15 @@ else fi if [ -z "$INTEGRATION_TEST_APP_NAME" ]; then - after_suite() { true; } + after_suite() { + true; + ps -aef --forest; + } else - after_suite() { killall $INTEGRATION_TEST_APP_NAME || true; } + after_suite() { + killall $INTEGRATION_TEST_APP_NAME || true; + ps -aef --forest; + } fi # Integration tests in AMD diff --git a/src/vs/platform/terminal/electron-browser/localPtyService.ts b/src/vs/platform/terminal/electron-browser/localPtyService.ts index d4c19fc86ef..e39be645dc7 100644 --- a/src/vs/platform/terminal/electron-browser/localPtyService.ts +++ b/src/vs/platform/terminal/electron-browser/localPtyService.ts @@ -5,14 +5,13 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { ILogService } from 'vs/platform/log/common/log'; -import { IPtyService, IProcessDataEvent, IShellLaunchConfig, ITerminalDimensionsOverride, ITerminalLaunchError } from 'vs/platform/terminal/common/terminal'; -// import { Client } from 'vs/base/parts/ipc/node/ipc.cp'; -// import { FileAccess } from 'vs/base/common/network'; -// import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc'; +import { IPtyService, IProcessDataEvent, IShellLaunchConfig, ITerminalDimensionsOverride, ITerminalLaunchError, TerminalIpcChannels } from 'vs/platform/terminal/common/terminal'; +import { Client } from 'vs/base/parts/ipc/node/ipc.cp'; +import { FileAccess } from 'vs/base/common/network'; +import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc'; import { IProcessEnvironment } from 'vs/base/common/platform'; import { Emitter } from 'vs/base/common/event'; -// import { LogLevelChannelClient } from 'vs/platform/log/common/logIpc'; -import { PtyService } from 'vs/platform/terminal/node/ptyService'; +import { LogLevelChannelClient } from 'vs/platform/log/common/logIpc'; // enum Constants { // MaxRestarts = 5 @@ -54,51 +53,50 @@ export class LocalPtyService extends Disposable implements IPtyService { } private _startPtyHost(): IPtyService { - // const client = this._register(new Client( - // FileAccess.asFileUri('bootstrap-fork', require).fsPath, - // { - // serverName: 'Pty Host', - // args: ['--type=ptyHost'], - // env: { - // VSCODE_AMD_ENTRYPOINT: 'vs/platform/terminal/node/ptyHostMain', - // VSCODE_PIPE_LOGGING: 'true', - // VSCODE_VERBOSE_LOGGING: 'true' // transmit console logs from server to client - // } - // } - // )); - // this._onPtyHostStart.fire(); + const client = this._register(new Client( + FileAccess.asFileUri('bootstrap-fork', require).fsPath, + { + serverName: 'Pty Host', + args: ['--type=ptyHost'], + env: { + VSCODE_AMD_ENTRYPOINT: 'vs/platform/terminal/node/ptyHostMain', + VSCODE_PIPE_LOGGING: 'true', + VSCODE_VERBOSE_LOGGING: 'true' // transmit console logs from server to client + } + } + )); + this._onPtyHostStart.fire(); - // // Handle exit - // this._register({ - // dispose: () => { - // if (proxy.shutdownAll) { - // proxy.shutdownAll(); - // } - // client.dispose(); - // } - // }); - // this._register(client.onDidProcessExit(e => { - // this._onPtyHostExit.fire(e.code); - // // if (!this._isDisposed) { - // // if (this._restartCount <= Constants.MaxRestarts) { - // // this._logService.error(`ptyHost terminated unexpectedly with code ${e.code}`); - // // this._restartCount++; - // // this._proxy = this._startPtyHost(); - // // } else { - // // this._logService.error(`ptyHost terminated unexpectedly with code ${e.code}, giving up`); - // // } - // // } - // })); + // Handle exit + this._register({ + dispose: () => { + if (proxy.shutdownAll) { + proxy.shutdownAll(); + } + client.dispose(); + } + }); + this._register(client.onDidProcessExit(e => { + this._onPtyHostExit.fire(e.code); + // if (!this._isDisposed) { + // if (this._restartCount <= Constants.MaxRestarts) { + // this._logService.error(`ptyHost terminated unexpectedly with code ${e.code}`); + // this._restartCount++; + // this._proxy = this._startPtyHost(); + // } else { + // this._logService.error(`ptyHost terminated unexpectedly with code ${e.code}, giving up`); + // } + // } + })); // Setup logging - // const logChannel = client.getChannel(TerminalIpcChannels.Log); - // this._register(this._logService.onDidChangeLogLevel(() => { - // LogLevelChannelClient.setLevel(logChannel, this._logService.getLevel()); - // })); + const logChannel = client.getChannel(TerminalIpcChannels.Log); + this._register(this._logService.onDidChangeLogLevel(() => { + LogLevelChannelClient.setLevel(logChannel, this._logService.getLevel()); + })); // Create proxy and forward events - const proxy = new PtyService(this._logService); - // const proxy = ProxyChannel.toService(client.getChannel(TerminalIpcChannels.PtyHost)); + const proxy = ProxyChannel.toService(client.getChannel(TerminalIpcChannels.PtyHost)); this._register(proxy.onProcessData(e => this._onProcessData.fire(e))); this._register(proxy.onProcessExit(e => this._onProcessExit.fire(e))); this._register(proxy.onProcessReady(e => this._onProcessReady.fire(e))); diff --git a/yarn.lock b/yarn.lock index 8695942fcec..f1705f10ebd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6672,10 +6672,10 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" -node-pty@0.10.0-beta19: - version "0.10.0-beta19" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.0-beta19.tgz#b7cbfba53f7b2a816efe8c9302dd083cc5874458" - integrity sha512-4UIOGMvpofUbe+ZniBUtY8zc/psMURSzbMonQgIhK7JlMQsUwcbkDIrKzStVLJX0FkeZpUNlsVtK7qqzHvrUZA== +node-pty@0.11.0-beta1: + version "0.11.0-beta1" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.11.0-beta1.tgz#961cf7ab56e0a689b71a19a46371ea090050f312" + integrity sha512-nHMB0K3LZTqjWv3X11XFdy/L4V2eMEk0RbmbVN02GPOkXdMy2NITI0px/x0JtNeIolRPq6r5hf5NUcNc2LJizw== dependencies: nan "^2.14.0" From 1a4c9ac9f2a68e1394af401a77c91b81965f5fb9 Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Fri, 12 Feb 2021 15:25:07 -0800 Subject: [PATCH 110/325] fix classic menubar safari --- src/vs/base/browser/ui/menu/menubar.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/base/browser/ui/menu/menubar.css b/src/vs/base/browser/ui/menu/menubar.css index bfa79a1c523..e6aa5f4ddbe 100644 --- a/src/vs/base/browser/ui/menu/menubar.css +++ b/src/vs/base/browser/ui/menu/menubar.css @@ -42,7 +42,7 @@ } .menubar .menubar-menu-items-holder { - position: absolute; + position: fixed; left: 0px; opacity: 1; z-index: 2000; From 8853436d0f977bdd9a366a395159ccf8957d37ab Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 15:36:00 -0800 Subject: [PATCH 111/325] Remove ps tree logging --- scripts/test-integration.sh | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index 610759621b6..b1d5e9588e3 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -55,15 +55,9 @@ else fi if [ -z "$INTEGRATION_TEST_APP_NAME" ]; then - after_suite() { - true; - ps -aef --forest; - } + after_suite() { true; } else - after_suite() { - killall $INTEGRATION_TEST_APP_NAME || true; - ps -aef --forest; - } + after_suite() { killall $INTEGRATION_TEST_APP_NAME || true; } fi # Integration tests in AMD From 2f277cb41eff4d30e09b17a72abb9c8afcb2b9de Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Fri, 12 Feb 2021 15:38:41 -0800 Subject: [PATCH 112/325] Add github session telemetry event --- .../github-authentication/src/extension.ts | 2 +- .../github-authentication/src/github.ts | 8 +++-- .../github-authentication/src/githubServer.ts | 35 +++++++++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/extensions/github-authentication/src/extension.ts b/extensions/github-authentication/src/extension.ts index df80913cd22..7ae1e1d2110 100644 --- a/extensions/github-authentication/src/extension.ts +++ b/extensions/github-authentication/src/extension.ts @@ -14,7 +14,7 @@ export async function activate(context: vscode.ExtensionContext) { const telemetryReporter = new TelemetryReporter(name, version, aiKey); context.subscriptions.push(vscode.window.registerUriHandler(uriHandler)); - const loginService = new GitHubAuthenticationProvider(context); + const loginService = new GitHubAuthenticationProvider(context, telemetryReporter); await loginService.initialize(context); diff --git a/extensions/github-authentication/src/github.ts b/extensions/github-authentication/src/github.ts index bf6cee27132..595d13147a1 100644 --- a/extensions/github-authentication/src/github.ts +++ b/extensions/github-authentication/src/github.ts @@ -9,6 +9,7 @@ import { Keychain } from './common/keychain'; import { GitHubServer, NETWORK_ERROR } from './githubServer'; import Logger from './common/logger'; import { arrayEquals } from './common/utils'; +import TelemetryReporter from 'vscode-extension-telemetry'; export const onDidChangeSessions = new vscode.EventEmitter(); @@ -25,12 +26,13 @@ interface SessionData { export class GitHubAuthenticationProvider { private _sessions: vscode.AuthenticationSession[] = []; - private _githubServer = new GitHubServer(); + private _githubServer: GitHubServer; private _keychain: Keychain; - constructor(context: vscode.ExtensionContext) { + constructor(context: vscode.ExtensionContext, telemetryReporter: TelemetryReporter) { this._keychain = new Keychain(context); + this._githubServer = new GitHubServer(telemetryReporter); } public async initialize(context: vscode.ExtensionContext): Promise { @@ -55,6 +57,7 @@ export class GitHubAuthenticationProvider { const verificationPromises = this._sessions.map(async session => { try { await this._githubServer.getUserInfo(session.accessToken); + this._githubServer.checkIsEdu(session.accessToken); verifiedSessions.push(session); } catch (e) { // Remove sessions that return unauthorized response @@ -163,6 +166,7 @@ export class GitHubAuthenticationProvider { public async createSession(scopes: string): Promise { const token = await this._githubServer.login(scopes); const session = await this.tokenToSession(token, scopes.split(' ')); + this._githubServer.checkIsEdu(token); await this.setToken(session); return session; } diff --git a/extensions/github-authentication/src/githubServer.ts b/extensions/github-authentication/src/githubServer.ts index b50285c9ab2..13ec13b735b 100644 --- a/extensions/github-authentication/src/githubServer.ts +++ b/extensions/github-authentication/src/githubServer.ts @@ -9,6 +9,7 @@ import fetch, { Response } from 'node-fetch'; import { v4 as uuid } from 'uuid'; import { PromiseAdapter, promiseFromEvent } from './common/utils'; import Logger from './common/logger'; +import TelemetryReporter from 'vscode-extension-telemetry'; const localize = nls.loadMessageBundle(); @@ -41,6 +42,8 @@ export class GitHubServer { private _pendingStates = new Map(); private _codeExchangePromises = new Map>(); + constructor(private readonly telemetryReporter: TelemetryReporter) { } + private isTestEnvironment(url: vscode.Uri): boolean { return url.authority === 'vscode-web-test-playground.azurewebsites.net' || url.authority.startsWith('localhost:'); } @@ -210,4 +213,36 @@ export class GitHubServer { throw new Error(result.statusText); } } + + public async checkIsEdu(token: string): Promise { + try { + const result = await fetch('https://education.github.com/api/user', { + headers: { + Authorization: `token ${token}`, + 'faculty-check-preview': 'true', + 'User-Agent': 'Visual-Studio-Code' + } + }); + + if (result.ok) { + const json: { student: boolean, faculty: boolean } = await result.json(); + + /* __GDPR__ + "session" : { + "isEdu": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryReporter.sendTelemetryEvent('session', { + isEdu: json.student + ? 'student' + : json.faculty + ? 'faculty' + : 'none' + }); + } + } catch (e) { + // No-op + } + + } } From be7cf6f2e9e43da36e26086a81feaf104b87949c Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Fri, 12 Feb 2021 15:41:37 -0800 Subject: [PATCH 113/325] use checkmark instead of toggle lang 4 diff editor --- src/vs/workbench/browser/parts/editor/editor.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index 003527d67e0..78d51af076a 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -464,7 +464,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCo MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.SPLIT_EDITOR_RIGHT, title: nls.localize('splitRight', "Split Right") }, group: '5_split', order: 40 }); // Editor Title Menu -MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.TOGGLE_DIFF_SIDE_BY_SIDE, title: nls.localize('toggleInlineView', "Toggle Inline View") }, group: '1_diff', order: 10, when: ContextKeyExpr.has('isInDiffEditor') }); +MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.TOGGLE_DIFF_SIDE_BY_SIDE, title: nls.localize('inlineView', "Inline View"), toggled: ContextKeyExpr.equals('config.diffEditor.renderSideBySide', false) }, group: '1_diff', order: 10, when: ContextKeyExpr.has('isInDiffEditor') }); MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.SHOW_EDITORS_IN_GROUP, title: nls.localize('showOpenedEditors', "Show Opened Editors") }, group: '3_open', order: 10 }); MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: nls.localize('closeAll', "Close All") }, group: '5_close', order: 10 }); MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.CLOSE_SAVED_EDITORS_COMMAND_ID, title: nls.localize('closeAllSaved', "Close Saved") }, group: '5_close', order: 20 }); From 0e16b7a0fe9f29dd4b7495d07f440961967669dd Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 15:59:54 -0800 Subject: [PATCH 114/325] Simplify echo works in the default shell --- .../src/singlefolder-tests/terminal.test.ts | 64 +++++++++---------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index 48615e433f6..6e9731fbfde 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { window, Pseudoterminal, EventEmitter, TerminalDimensions, workspace, ConfigurationTarget, Disposable, UIKind, env, EnvironmentVariableMutatorType, EnvironmentVariableMutator, extensions, ExtensionContext, TerminalOptions, ExtensionTerminalOptions, Terminal } from 'vscode'; -import { doesNotThrow, equal, deepEqual, throws } from 'assert'; +import { doesNotThrow, equal, deepEqual, throws, strictEqual } from 'assert'; import { assertNoRpc } from '../utils'; // Disable terminal tests: @@ -55,42 +55,28 @@ import { assertNoRpc } from '../utils'; }); }); - (process.platform === 'linux' ? test.skip : test.skip)('echo works in the default shell', (done) => { - disposables.push(window.onDidOpenTerminal(term => { - try { - equal(terminal, term); - } catch (e) { - done(e); - return; - } - let data = ''; - const dataDisposable = window.onDidWriteTerminalData(e => { - try { - equal(terminal, e.terminal); - } catch (e) { - done(e); - return; - } - data += e.data; - if (data.indexOf(expected) !== 0) { - dataDisposable.dispose(); - terminal.dispose(); - disposables.push(window.onDidCloseTerminal(() => { - done(); - })); - } + test('echo works in the default shell', async () => { + const terminal = await new Promise(r => { + disposables.push(window.onDidOpenTerminal(t => { + strictEqual(terminal, t); + r(terminal); + })); + // Use a single character to avoid winpty/conpty issues with injected sequences + const terminal = window.createTerminal({ + env: { TEST: '`' } }); - disposables.push(dataDisposable); - })); - // Use a single character to avoid winpty/conpty issues with injected sequences - const expected = '`'; - const terminal = window.createTerminal({ - env: { - TEST: '`' - } + terminal.show(); }); - terminal.show(); - doesNotThrow(() => { + + let data = ''; + await new Promise(r => { + disposables.push(window.onDidWriteTerminalData(e => { + strictEqual(terminal, e.terminal); + data += e.data; + if (data.indexOf('`') !== 0) { + r(); + } + })); // Print an environment variable value so the echo statement doesn't get matched if (process.platform === 'win32') { terminal.sendText(`$env:TEST`); @@ -98,6 +84,14 @@ import { assertNoRpc } from '../utils'; terminal.sendText(`echo $TEST`); } }); + + await new Promise(r => { + terminal.dispose(); + disposables.push(window.onDidCloseTerminal(t => { + strictEqual(terminal, t); + r(); + })); + }); }); test('onDidCloseTerminal event fires when terminal is disposed', async () => { From 07e3bcf7eacfb5a3f9c6e426fc977d176e40a726 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 12 Feb 2021 15:01:11 -0800 Subject: [PATCH 115/325] testing: allow filtering to only executed or failed tests --- .../testing/browser/testingExplorerFilter.ts | 29 +++++++++++++++++-- .../testing/browser/testingExplorerView.ts | 21 ++++++++++++-- .../contrib/testing/common/constants.ts | 6 ++++ 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts index eae8ec3d55d..3c102a91fd5 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts @@ -9,7 +9,7 @@ import { BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem'; import { HistoryInputBox } from 'vs/base/browser/ui/inputbox/inputBox'; -import { Action, IAction, IActionRunner } from 'vs/base/common/actions'; +import { Action, IAction, IActionRunner, Separator } from 'vs/base/common/actions'; import { Delayer } from 'vs/base/common/async'; import { Emitter, Event } from 'vs/base/common/event'; import { KeyCode } from 'vs/base/common/keyCodes'; @@ -24,7 +24,7 @@ import { attachInputBoxStyler } from 'vs/platform/theme/common/styler'; import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService'; import { ViewContainerLocation } from 'vs/workbench/common/views'; import { testingFilterIcon } from 'vs/workbench/contrib/testing/browser/icons'; -import { Testing } from 'vs/workbench/contrib/testing/common/constants'; +import { TestExplorerStateFilter, Testing } from 'vs/workbench/contrib/testing/common/constants'; import { ObservableValue } from 'vs/workbench/contrib/testing/common/observableValue'; import { StoredValue } from 'vs/workbench/contrib/testing/common/storedValue'; import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys'; @@ -34,6 +34,7 @@ export interface ITestExplorerFilterState { readonly text: ObservableValue; /** Reveal request, the extId of the test to reveal */ readonly reveal: ObservableValue; + readonly stateFilter: ObservableValue; readonly currentDocumentOnly: ObservableValue; readonly onDidRequestInputFocus: Event; @@ -46,6 +47,11 @@ export class TestExplorerFilterState implements ITestExplorerFilterState { declare _serviceBrand: undefined; private readonly focusEmitter = new Emitter(); public readonly text = new ObservableValue(''); + public readonly stateFilter = ObservableValue.stored(new StoredValue({ + key: 'testStateFilter', + scope: StorageScope.WORKSPACE, + target: StorageTarget.USER + }, this.storage), TestExplorerStateFilter.All); public readonly currentDocumentOnly = ObservableValue.stored(new StoredValue({ key: 'testsByCurrentDocumentOnly', scope: StorageScope.WORKSPACE, @@ -83,6 +89,7 @@ export class TestingExplorerFilter extends BaseActionViewItem { super(null, action); this.updateFilterActiveState(); this._register(state.currentDocumentOnly.onDidChange(this.updateFilterActiveState, this)); + this._register(state.stateFilter.onDidChange(this.updateFilterActiveState, this)); } /** @@ -166,7 +173,8 @@ export class TestingExplorerFilter extends BaseActionViewItem { * Updates the 'checked' state of the filter submenu. */ private updateFilterActiveState() { - this.filtersAction.checked = this.state.currentDocumentOnly.value; + this.filtersAction.checked = this.state.currentDocumentOnly.value + || this.state.stateFilter.value !== TestExplorerStateFilter.All; } } @@ -198,6 +206,21 @@ class FiltersDropdownMenuActionViewItem extends DropdownMenuActionViewItem { private getActions(): IAction[] { return [ + ...[ + { v: TestExplorerStateFilter.OnlyFailed, label: localize('testing.filters.showOnlyFailed', "Show Only Failed Tests") }, + { v: TestExplorerStateFilter.OnlyExecuted, label: localize('testing.filters.showOnlyExecuted', "Show Only Executed Tests") }, + { v: TestExplorerStateFilter.All, label: localize('testing.filters.showAll', "Show All Tests") }, + ].map(({ v, label }) => ({ + checked: this.filters.stateFilter.value === v, + class: undefined, + enabled: true, + id: v, + label, + run: async () => this.filters.stateFilter.value = v, + tooltip: '', + dispose: () => null + })), + new Separator(), { checked: this.filters.currentDocumentOnly.value, class: undefined, diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts index 444e96c7b1c..aa396f4e514 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts @@ -51,7 +51,7 @@ import { HierarchicalByNameProjection } from 'vs/workbench/contrib/testing/brows import { testingStatesToIcons } from 'vs/workbench/contrib/testing/browser/icons'; import { ITestExplorerFilterState, TestExplorerFilterState, TestingExplorerFilter } from 'vs/workbench/contrib/testing/browser/testingExplorerFilter'; import { ITestingPeekOpener, TestingOutputPeekController } from 'vs/workbench/contrib/testing/browser/testingOutputPeek'; -import { TestExplorerViewMode, TestExplorerViewSorting, Testing, testStateNames } from 'vs/workbench/contrib/testing/common/constants'; +import { TestExplorerStateFilter, TestExplorerViewMode, TestExplorerViewSorting, Testing, testStateNames } from 'vs/workbench/contrib/testing/common/constants'; import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys'; import { cmpPriority, isFailedState } from 'vs/workbench/contrib/testing/common/testingStates'; import { ITestResultService, sumCounts, TestStateCount } from 'vs/workbench/contrib/testing/common/testResultService'; @@ -257,7 +257,11 @@ export class TestingExplorerViewModel extends Disposable { filter: this.filter, }) as WorkbenchObjectTree; - this._register(Event.any(filterState.currentDocumentOnly.onDidChange, filterState.text.onDidChange)(this.tree.refilter, this.tree)); + this._register(Event.any( + filterState.currentDocumentOnly.onDidChange, + filterState.text.onDidChange, + filterState.stateFilter.onDidChange, + )(this.tree.refilter, this.tree)); this._register(editorService.onDidActiveEditorChange(() => { if (filterState.currentDocumentOnly.value && editorService.activeEditor?.resource) { if (this.projection.hasTestInDocument(editorService.activeEditor.resource)) { @@ -523,7 +527,7 @@ class TestsFilter implements ITreeFilter { this.setFilter(this.state.text.value); } - switch (Math.min(this.testFilterText(element), this.testLocation(element))) { + switch (Math.min(this.testFilterText(element), this.testLocation(element), this.testState(element))) { case FilterResult.Exclude: return TreeVisibility.Hidden; case FilterResult.Include: @@ -533,6 +537,17 @@ class TestsFilter implements ITreeFilter { } } + private testState(element: ITestTreeElement): FilterResult { + switch (this.state.stateFilter.value) { + case TestExplorerStateFilter.All: + return FilterResult.Include; + case TestExplorerStateFilter.OnlyExecuted: + return element.ownState !== TestRunState.Unset ? FilterResult.Include : FilterResult.Inherit; + case TestExplorerStateFilter.OnlyFailed: + return isFailedState(element.ownState) ? FilterResult.Include : FilterResult.Inherit; + } + } + private testLocation(element: ITestTreeElement): FilterResult { if (!this._filterToUri || !this.state.currentDocumentOnly.value) { return FilterResult.Include; diff --git a/src/vs/workbench/contrib/testing/common/constants.ts b/src/vs/workbench/contrib/testing/common/constants.ts index 817cef54b7e..0e6ebdae3ba 100644 --- a/src/vs/workbench/contrib/testing/common/constants.ts +++ b/src/vs/workbench/contrib/testing/common/constants.ts @@ -25,6 +25,12 @@ export const enum TestExplorerViewSorting { ByName = 'name', } +export const enum TestExplorerStateFilter { + OnlyFailed = 'failed', + OnlyExecuted = 'excuted', + All = 'all', +} + export const testStateNames: { [K in TestRunState]: string } = { [TestRunState.Errored]: localize('testState.errored', 'Errored'), [TestRunState.Failed]: localize('testState.failed', 'Failed'), From a0e0324a8daad1b7f5a9e2ed7f174ded9186a3aa Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 12 Feb 2021 16:08:57 -0800 Subject: [PATCH 116/325] testing: commands to run tests at current cursor and in file Refs https://github.com/microsoft/vscode/issues/116589 --- .../api/browser/mainThreadTesting.ts | 3 + .../api/common/extHostTypeConverters.ts | 4 +- .../explorerProjections/locationStore.ts | 20 +- .../testing/browser/testExplorerActions.ts | 173 +++++++++++++++++- .../testing/browser/testing.contribution.ts | 4 + .../testing/browser/testingDecorations.ts | 9 +- .../contrib/testing/common/testCollection.ts | 14 +- .../testing/common/testResultService.ts | 7 + .../contrib/testing/common/testService.ts | 17 ++ 9 files changed, 223 insertions(+), 28 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadTesting.ts b/src/vs/workbench/api/browser/mainThreadTesting.ts index 95fc3e9ae7f..110becb9583 100644 --- a/src/vs/workbench/api/browser/mainThreadTesting.ts +++ b/src/vs/workbench/api/browser/mainThreadTesting.ts @@ -6,6 +6,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { URI, UriComponents } from 'vs/base/common/uri'; +import { Range } from 'vs/editor/common/core/range'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { getTestSubscriptionKey, ITestState, RunTestsRequest, TestDiffOpType, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection'; import { ITestResultService, LiveTestResult } from 'vs/workbench/contrib/testing/common/testResultService'; @@ -18,6 +19,7 @@ const reviveDiff = (diff: TestsDiff) => { const item = entry[1]; if (item.item.location) { item.item.location.uri = URI.revive(item.item.location.uri); + item.item.location.range = Range.lift(item.item.location.range); } } } @@ -71,6 +73,7 @@ export class MainThreadTesting extends Disposable implements MainThreadTestingSh for (const message of state.messages) { if (message.location) { message.location.uri = URI.revive(message.location.uri); + message.location.range = Range.lift(message.location.range); } } diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 9799bddf7bd..e838b45bfb9 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -1507,7 +1507,7 @@ export namespace TestState { severity: message.severity, expectedOutput: message.expectedOutput, actualOutput: message.actualOutput, - location: message.location ? location.from(message.location) : undefined, + location: message.location ? location.from(message.location) as any : undefined, })) ?? [], }; } @@ -1536,7 +1536,7 @@ export namespace TestItem { return { extId: item.id ?? (parentExtId ? `${parentExtId}\0${item.label}` : item.label), label: item.label, - location: item.location ? location.from(item.location) : undefined, + location: item.location ? location.from(item.location) as any : undefined, debuggable: item.debuggable ?? false, description: item.description, runnable: item.runnable ?? true, diff --git a/src/vs/workbench/contrib/testing/browser/explorerProjections/locationStore.ts b/src/vs/workbench/contrib/testing/browser/explorerProjections/locationStore.ts index 9e23c907a81..f604a164eec 100644 --- a/src/vs/workbench/contrib/testing/browser/explorerProjections/locationStore.ts +++ b/src/vs/workbench/contrib/testing/browser/explorerProjections/locationStore.ts @@ -6,25 +6,22 @@ import { findFirstInSorted } from 'vs/base/common/arrays'; import { URI } from 'vs/base/common/uri'; import { Position } from 'vs/editor/common/core/position'; -import { Location as ModeLocation } from 'vs/editor/common/modes'; +import { Range } from 'vs/editor/common/core/range'; +import { IRichLocation } from 'vs/workbench/contrib/testing/common/testCollection'; -export const locationsEqual = (a: ModeLocation | undefined, b: ModeLocation | undefined) => { +export const locationsEqual = (a: IRichLocation | undefined, b: IRichLocation | undefined) => { if (a === undefined || b === undefined) { return b === a; } - return a.uri.toString() === b.uri.toString() - && a.range.startLineNumber === b.range.startLineNumber - && a.range.startColumn === b.range.startColumn - && a.range.endLineNumber === b.range.endLineNumber - && a.range.endColumn === b.range.endColumn; + return a.uri.toString() === b.uri.toString() && a.range.equalsRange(b.range); }; /** * Stores and looks up test-item-like-objects by their uri/range. Used to * implement the 'reveal' action efficiently. */ -export class TestLocationStore { +export class TestLocationStore { private readonly itemsByUri = new Map(); public hasTestInDocument(uri: URI) { @@ -39,12 +36,7 @@ export class TestLocationStore { const range = test.location?.range; - return range - && new Position(range.startLineNumber, range.startColumn).isBeforeOrEqual(position) - && position.isBeforeOrEqual(new Position( - range.endLineNumber ?? range.startLineNumber, - range.endColumn ?? range.startColumn, - )); + return range && Range.lift(range).containsPosition(position); }); } diff --git a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts index 60ffcfc38c0..2dac0056fb6 100644 --- a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts +++ b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts @@ -26,8 +26,9 @@ import { InternalTestItem, TestIdWithProvider } from 'vs/workbench/contrib/testi import { ITestingAutoRun } from 'vs/workbench/contrib/testing/common/testingAutoRun'; import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys'; import { ITestResult, ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService'; -import { ITestService, waitForAllRoots } from 'vs/workbench/contrib/testing/common/testService'; +import { ITestService, waitForAllRoots, waitForAllTests } from 'vs/workbench/contrib/testing/common/testService'; import { IWorkspaceTestCollectionService } from 'vs/workbench/contrib/testing/common/workspaceTestCollectionService'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; const category = localize('testing.category', 'Test'); @@ -94,7 +95,7 @@ export class RunAction extends Action { } } -abstract class RunOrDebugAction extends ViewAction { +abstract class RunOrDebugSelectedAction extends ViewAction { constructor(id: string, title: string, icon: ThemeIcon, private readonly debug: boolean) { super({ id, @@ -103,6 +104,7 @@ abstract class RunOrDebugAction extends ViewAction { viewId: Testing.ExplorerViewId, f1: true, category, + precondition: FocusedViewContext.isEqualTo(Testing.ExplorerViewId), }); } @@ -143,7 +145,7 @@ abstract class RunOrDebugAction extends ViewAction { protected abstract filter(item: InternalTestItem): boolean; } -export class RunSelectedAction extends RunOrDebugAction { +export class RunSelectedAction extends RunOrDebugSelectedAction { constructor( ) { super( @@ -162,7 +164,7 @@ export class RunSelectedAction extends RunOrDebugAction { } } -export class DebugSelectedAction extends RunOrDebugAction { +export class DebugSelectedAction extends RunOrDebugSelectedAction { constructor() { super( 'testing.debugSelected', @@ -502,3 +504,166 @@ export class ToggleAutoRun extends Action2 { accessor.get(ITestingAutoRun).toggle(); } } + +abstract class RunOrDebugAtCursor extends Action2 { + /** + * @override + */ + public async run(accessor: ServicesAccessor) { + const control = accessor.get(IEditorService).activeTextEditorControl; + const position = control?.getPosition(); + const model = control?.getModel(); + if (!position || !model || !('uri' in model)) { + return; + } + + + const testService = accessor.get(ITestService); + const collection = testService.subscribeToDiffs(ExtHostTestingResource.TextDocument, model.uri); + + let bestDepth = -1; + let bestNode: InternalTestItem | undefined; + + try { + await waitForAllTests(collection.object); + const queue: [depth: number, nodes: Iterable][] = [[0, collection.object.rootIds]]; + while (queue.length > 0) { + const [depth, candidates] = queue.pop()!; + for (const id of candidates) { + const candidate = collection.object.getNodeById(id); + if (candidate) { + if (depth > bestDepth && this.filter(candidate) && candidate.item.location?.range.containsPosition(position)) { + bestDepth = depth; + bestNode = candidate; + } + + queue.push([depth + 1, candidate.children]); + } + } + } + + if (bestNode) { + await this.runTest(testService, bestNode); + } + } finally { + collection.dispose(); + } + } + + protected abstract filter(node: InternalTestItem): boolean; + + protected abstract runTest(service: ITestService, node: InternalTestItem): Promise; +} + +export class RunAtCursor extends RunOrDebugAtCursor { + constructor() { + super({ + id: 'testing.runAtCursor', + title: localize('testing.runAtCursor', "Run Test at Cursor"), + f1: true, + category, + }); + } + + protected filter(node: InternalTestItem): boolean { + return node.item.runnable; + } + + protected runTest(service: ITestService, node: InternalTestItem): Promise { + return service.runTests({ debug: false, tests: [{ testId: node.id, providerId: node.providerId }] }); + } +} + +export class DebugAtCursor extends RunOrDebugAtCursor { + constructor() { + super({ + id: 'testing.debugAtCursor', + title: localize('testing.debugAtCursor', "Debug Test at Cursor"), + f1: true, + category, + }); + } + + protected filter(node: InternalTestItem): boolean { + return node.item.debuggable; + } + + protected runTest(service: ITestService, node: InternalTestItem): Promise { + return service.runTests({ debug: true, tests: [{ testId: node.id, providerId: node.providerId }] }); + } +} + + +abstract class RunOrDebugCurrentFile extends Action2 { + /** + * @override + */ + public async run(accessor: ServicesAccessor) { + const control = accessor.get(IEditorService).activeTextEditorControl; + const position = control?.getPosition(); + const model = control?.getModel(); + if (!position || !model || !('uri' in model)) { + return; + } + + const testService = accessor.get(ITestService); + const collection = testService.subscribeToDiffs(ExtHostTestingResource.TextDocument, model.uri); + + try { + await waitForAllTests(collection.object); + + const roots = [...collection.object.rootIds] + .map(r => collection.object.getNodeById(r)) + .filter(isDefined) + .filter(n => this.filter(n)); + + if (roots.length) { + await this.runTest(testService, roots); + } + } finally { + collection.dispose(); + } + } + + protected abstract filter(node: InternalTestItem): boolean; + + protected abstract runTest(service: ITestService, node: InternalTestItem[]): Promise; +} + +export class RunCurrentFile extends RunOrDebugCurrentFile { + constructor() { + super({ + id: 'testing.runCurrentFile', + title: localize('testing.runCurrentFile', "Run Tests in Current File"), + f1: true, + category, + }); + } + + protected filter(node: InternalTestItem): boolean { + return node.item.runnable; + } + + protected runTest(service: ITestService, nodes: InternalTestItem[]): Promise { + return service.runTests({ debug: false, tests: nodes.map(node => ({ testId: node.id, providerId: node.providerId })) }); + } +} + +export class DebugCurrentFile extends RunOrDebugCurrentFile { + constructor() { + super({ + id: 'testing.debugCurrentFile', + title: localize('testing.debugCurrentFile', "Debug Tests in Current File"), + f1: true, + category, + }); + } + + protected filter(node: InternalTestItem): boolean { + return node.item.debuggable; + } + + protected runTest(service: ITestService, nodes: InternalTestItem[]): Promise { + return service.runTests({ debug: true, tests: nodes.map(node => ({ testId: node.id, providerId: node.providerId })) }); + } +} diff --git a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts index 8a9600b6b63..6ef650fcedf 100644 --- a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts +++ b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts @@ -97,6 +97,10 @@ registerAction2(Action.DebugAllAction); registerAction2(Action.EditFocusedTest); registerAction2(Action.ClearTestResultsAction); registerAction2(Action.ToggleAutoRun); +registerAction2(Action.DebugAtCursor); +registerAction2(Action.RunAtCursor); +registerAction2(Action.DebugCurrentFile); +registerAction2(Action.RunCurrentFile); registerAction2(CloseTestPeek); Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TestingContentProvider, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts index 6006946567f..567258a3597 100644 --- a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts +++ b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts @@ -14,7 +14,6 @@ import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { IRange } from 'vs/editor/common/core/range'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { IModelDeltaDecoration, OverviewRulerLane, TrackedRangeStickiness } from 'vs/editor/common/model'; -import { Location as ModeLocation } from 'vs/editor/common/modes'; import { overviewRulerError, overviewRulerInfo, overviewRulerWarning } from 'vs/editor/common/view/editorColorRegistry'; import { localize } from 'vs/nls'; import { ICommandService } from 'vs/platform/commands/common/commands'; @@ -27,7 +26,7 @@ import { BREAKPOINT_EDITOR_CONTRIBUTION_ID, IBreakpointEditorContribution } from import { testingRunAllIcon, testingRunIcon, testingStatesToIcons } from 'vs/workbench/contrib/testing/browser/icons'; import { TestingOutputPeekController } from 'vs/workbench/contrib/testing/browser/testingOutputPeek'; import { testMessageSeverityColors } from 'vs/workbench/contrib/testing/browser/theme'; -import { IncrementalTestCollectionItem, ITestMessage } from 'vs/workbench/contrib/testing/common/testCollection'; +import { IncrementalTestCollectionItem, IRichLocation, ITestMessage } from 'vs/workbench/contrib/testing/common/testCollection'; import { buildTestUri, TestUriType } from 'vs/workbench/contrib/testing/common/testingUri'; import { ITestResultService, TestResultItem } from 'vs/workbench/contrib/testing/common/testResultService'; import { IMainThreadTestCollection, ITestService } from 'vs/workbench/contrib/testing/common/testService'; @@ -144,7 +143,7 @@ interface ITestDecoration extends IDisposable { click(e: IEditorMouseEvent): boolean; } -const hasValidLocation = (editorUri: URI, t: T): t is T & { location: ModeLocation } => +const hasValidLocation = (editorUri: URI, t: T): t is T & { location: IRichLocation } => t.location?.uri.toString() === editorUri.toString(); const firstLineRange = (originalRange: IRange) => ({ @@ -170,7 +169,7 @@ class RunTestDecoration extends Disposable implements ITestDecoration { constructor( private readonly test: IncrementalTestCollectionItem, private readonly collection: IMainThreadTestCollection, - private readonly location: ModeLocation, + private readonly location: IRichLocation, private readonly editor: ICodeEditor, stateItem: TestResultItem | undefined, @ITestService private readonly testService: ITestService, @@ -282,7 +281,7 @@ class TestMessageDecoration implements ITestDecoration { constructor( { message, severity }: ITestMessage, private readonly messageUri: URI, - location: ModeLocation, + location: IRichLocation, private readonly editor: ICodeEditor, @ICodeEditorService private readonly editorService: ICodeEditorService, @IThemeService themeService: IThemeService, diff --git a/src/vs/workbench/contrib/testing/common/testCollection.ts b/src/vs/workbench/contrib/testing/common/testCollection.ts index b90a86c393e..e42f8a207a9 100644 --- a/src/vs/workbench/contrib/testing/common/testCollection.ts +++ b/src/vs/workbench/contrib/testing/common/testCollection.ts @@ -5,7 +5,7 @@ import { IMarkdownString } from 'vs/base/common/htmlContent'; import { URI } from 'vs/base/common/uri'; -import { Location as ModeLocation } from 'vs/editor/common/modes'; +import { Range } from 'vs/editor/common/core/range'; import { ExtHostTestingResource } from 'vs/workbench/api/common/extHost.protocol'; import { TestMessageSeverity, TestRunState } from 'vs/workbench/api/common/extHostTypes'; @@ -33,12 +33,20 @@ export interface RunTestForProviderRequest { debug: boolean; } +/** + * Location with a fully-instantiated Range and URI. + */ +export interface IRichLocation { + range: Range; + uri: URI; +} + export interface ITestMessage { message: string | IMarkdownString; severity: TestMessageSeverity | undefined; expectedOutput: string | undefined; actualOutput: string | undefined; - location: ModeLocation | undefined; + location: IRichLocation | undefined; } export interface ITestState { @@ -55,7 +63,7 @@ export interface ITestItem { extId: string; label: string; children?: never; - location: ModeLocation | undefined; + location: IRichLocation | undefined; description: string | undefined; runnable: boolean; debuggable: boolean; diff --git a/src/vs/workbench/contrib/testing/common/testResultService.ts b/src/vs/workbench/contrib/testing/common/testResultService.ts index 371d312c767..c380e53708b 100644 --- a/src/vs/workbench/contrib/testing/common/testResultService.ts +++ b/src/vs/workbench/contrib/testing/common/testResultService.ts @@ -6,6 +6,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; +import { Range } from 'vs/editor/common/core/range'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; @@ -426,9 +427,15 @@ class HydratedTestResult implements ITestResult { for (const item of serialized.items) { const cast: TestResultItem = { ...item, retired: true, children: new Set(item.children) }; + if (cast.item.location) { + cast.item.location.uri = URI.revive(cast.item.location.uri); + cast.item.location.range = Range.lift(cast.item.location.range); + } + for (const message of cast.state.messages) { if (message.location) { message.location.uri = URI.revive(message.location.uri); + message.location.range = Range.lift(message.location.range); } } diff --git a/src/vs/workbench/contrib/testing/common/testService.ts b/src/vs/workbench/contrib/testing/common/testService.ts index 61639ba1874..8d1e5221dde 100644 --- a/src/vs/workbench/contrib/testing/common/testService.ts +++ b/src/vs/workbench/contrib/testing/common/testService.ts @@ -74,6 +74,23 @@ export const waitForAllRoots = (collection: IMainThreadTestCollection, timeout = }).finally(() => listener.dispose()); }; +export const waitForAllTests = (collection: IMainThreadTestCollection, timeout = 3000) => { + if (collection.busyProviders === 0) { + return Promise.resolve(); + } + + let listener: IDisposable; + return new Promise(resolve => { + listener = collection.onBusyProvidersChange(count => { + if (count === 0) { + resolve(); + } + }); + + setTimeout(resolve, timeout); + }).finally(() => listener.dispose()); +}; + export interface ITestService { readonly _serviceBrand: undefined; readonly onShouldSubscribe: Event<{ resource: ExtHostTestingResource, uri: URI; }>; From 90f344fe7ef2bd56a663c26a338deef3286167c4 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 12 Feb 2021 17:05:24 -0800 Subject: [PATCH 117/325] Skip echo test again --- .../vscode-api-tests/src/singlefolder-tests/terminal.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index 6e9731fbfde..5565059085c 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -55,7 +55,7 @@ import { assertNoRpc } from '../utils'; }); }); - test('echo works in the default shell', async () => { + test.skip('echo works in the default shell', async () => { const terminal = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { strictEqual(terminal, t); From 647a4b044a2947a5043c67915b1e785400abfa22 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 12 Feb 2021 18:24:17 -0800 Subject: [PATCH 118/325] Make sure we focus inner iframe contents if the webview itself is already focused --- src/vs/workbench/contrib/webview/browser/pre/main.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/contrib/webview/browser/pre/main.js b/src/vs/workbench/contrib/webview/browser/pre/main.js index cc3bc25eab0..2d4ac83084a 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/main.js +++ b/src/vs/workbench/contrib/webview/browser/pre/main.js @@ -591,6 +591,10 @@ contentWindow.addEventListener('scroll', handleInnerScroll); contentWindow.addEventListener('wheel', handleWheel); + if (document.hasFocus()) { + contentWindow.focus(); + } + pendingMessages.forEach((data) => { contentWindow.postMessage(data, '*'); }); From 992cf6bd44d89f85b50199d52ff34ca14fd5358f Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Sat, 13 Feb 2021 10:28:08 +0100 Subject: [PATCH 119/325] Update node-fetch (#116560) --- extensions/github-authentication/package.json | 2 +- extensions/github-authentication/yarn.lock | 8 ++++---- extensions/github/yarn.lock | 6 +++--- extensions/microsoft-authentication/package.json | 2 +- extensions/microsoft-authentication/yarn.lock | 8 ++++---- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/extensions/github-authentication/package.json b/extensions/github-authentication/package.json index 0fe917632fe..726949d02e0 100644 --- a/extensions/github-authentication/package.json +++ b/extensions/github-authentication/package.json @@ -53,7 +53,7 @@ "vscode:prepublish": "npm run compile" }, "dependencies": { - "node-fetch": "2.6.0", + "node-fetch": "2.6.1", "uuid": "8.1.0", "vscode-extension-telemetry": "0.1.1", "vscode-nls": "^4.1.2" diff --git a/extensions/github-authentication/yarn.lock b/extensions/github-authentication/yarn.lock index 1da6beed526..5220f268c51 100644 --- a/extensions/github-authentication/yarn.lock +++ b/extensions/github-authentication/yarn.lock @@ -84,10 +84,10 @@ mime-types@^2.1.12: dependencies: mime-db "1.44.0" -node-fetch@2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" - integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== +node-fetch@2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== semver@^5.3.0: version "5.7.1" diff --git a/extensions/github/yarn.lock b/extensions/github/yarn.lock index 5e790ac2903..05a0b4cf6f9 100644 --- a/extensions/github/yarn.lock +++ b/extensions/github/yarn.lock @@ -125,9 +125,9 @@ is-plain-object@^3.0.0: integrity sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g== node-fetch@^2.3.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" - integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== once@^1.4.0: version "1.4.0" diff --git a/extensions/microsoft-authentication/package.json b/extensions/microsoft-authentication/package.json index e6416410be3..54405b6939f 100644 --- a/extensions/microsoft-authentication/package.json +++ b/extensions/microsoft-authentication/package.json @@ -47,7 +47,7 @@ }, "dependencies": { "buffer": "^5.6.0", - "node-fetch": "^2.6.0", + "node-fetch": "2.6.1", "randombytes": "github:rmacfarlane/randombytes#b28d4ecee46262801ea09f15fa1f1513a05c5971", "sha.js": "2.4.11", "stream": "0.0.2", diff --git a/extensions/microsoft-authentication/yarn.lock b/extensions/microsoft-authentication/yarn.lock index 58e34ee843a..b58b488d970 100644 --- a/extensions/microsoft-authentication/yarn.lock +++ b/extensions/microsoft-authentication/yarn.lock @@ -126,10 +126,10 @@ mime-types@^2.1.12: dependencies: mime-db "1.44.0" -node-fetch@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" - integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== +node-fetch@2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== "randombytes@github:rmacfarlane/randombytes#b28d4ecee46262801ea09f15fa1f1513a05c5971": version "2.1.0" From 05922f8a260c3731abdaedfcab1b546c6c691986 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sat, 13 Feb 2021 10:44:21 +0100 Subject: [PATCH 120/325] storage - add tests for all services --- .eslintrc.json | 1 + .../storageService.test.ts} | 56 ++++--- .../test/common/storageService.test.ts | 149 ++++++++++-------- .../storage/test/node/storageService.test.ts | 54 ++++--- 4 files changed, 149 insertions(+), 111 deletions(-) rename src/vs/platform/storage/test/{electron-browser/storage.test.ts => browser/storageService.test.ts} (54%) diff --git a/.eslintrc.json b/.eslintrc.json index cf4c1418a11..09fa5a59cde 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -278,6 +278,7 @@ "sinon", "vs/nls", "**/vs/base/{common,browser}/**", + "**/vs/base/parts/*/{common,browser}/**", "**/vs/platform/*/{common,browser}/**", "**/vs/platform/*/test/{common,browser}/**" ] diff --git a/src/vs/platform/storage/test/electron-browser/storage.test.ts b/src/vs/platform/storage/test/browser/storageService.test.ts similarity index 54% rename from src/vs/platform/storage/test/electron-browser/storage.test.ts rename to src/vs/platform/storage/test/browser/storageService.test.ts index 836f287788c..fdeb01f61c6 100644 --- a/src/vs/platform/storage/test/electron-browser/storage.test.ts +++ b/src/vs/platform/storage/test/browser/storageService.test.ts @@ -4,25 +4,45 @@ *--------------------------------------------------------------------------------------------*/ import { strictEqual } from 'assert'; -import { FileStorageDatabase } from 'vs/platform/storage/browser/storageService'; -import { join } from 'vs/base/common/path'; -import { tmpdir } from 'os'; -import { rimraf } from 'vs/base/node/pfs'; +import { BrowserStorageService, FileStorageDatabase } from 'vs/platform/storage/browser/storageService'; import { NullLogService } from 'vs/platform/log/common/log'; import { Storage } from 'vs/base/parts/storage/common/storage'; import { URI } from 'vs/base/common/uri'; import { FileService } from 'vs/platform/files/common/fileService'; -import { getRandomTestPath } from 'vs/base/test/node/testUtils'; -import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; +import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider'; +import { createSuite } from 'vs/platform/storage/test/common/storageService.test'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -suite('Storage', () => { +suite('StorageService (browser)', function () { - let testDir: string; + const disposables = new DisposableStore(); + + createSuite({ + setup: async () => { + const logService = new NullLogService(); + + const fileService = disposables.add(new FileService(logService)); + + const userDataProvider = disposables.add(new InMemoryFileSystemProvider()); + disposables.add(fileService.registerProvider(Schemas.userData, userDataProvider)); + + const storageService = disposables.add(new BrowserStorageService({ userRoamingDataHome: URI.file('/User').with({ scheme: Schemas.userData }) } as unknown as IEnvironmentService, fileService)); + + await storageService.initialize({ id: String(Date.now()) }); + + return storageService; + }, + teardown: async storage => { + disposables.clear(); + } + }); +}); + +suite('FileStorageDatabase (browser)', () => { let fileService: FileService; - let fileProvider: DiskFileSystemProvider; const disposables = new DisposableStore(); @@ -31,20 +51,18 @@ suite('Storage', () => { fileService = disposables.add(new FileService(logService)); - fileProvider = disposables.add(new DiskFileSystemProvider(logService)); - disposables.add(fileService.registerProvider(Schemas.file, fileProvider)); - - testDir = getRandomTestPath(tmpdir(), 'vsctests', 'storageservice'); + const userDataProvider = disposables.add(new InMemoryFileSystemProvider()); + disposables.add(fileService.registerProvider(Schemas.userData, userDataProvider)); }); teardown(() => { disposables.clear(); - - return rimraf(testDir); }); - test('File Based Storage', async () => { - let storage = new Storage(new FileStorageDatabase(URI.file(join(testDir, 'storage.json')), false, fileService)); + test('Basics', async () => { + const testDir = URI.file('/User/storage.json').with({ scheme: Schemas.userData }); + + let storage = new Storage(new FileStorageDatabase(testDir, false, fileService)); await storage.init(); @@ -58,7 +76,7 @@ suite('Storage', () => { await storage.close(); - storage = new Storage(new FileStorageDatabase(URI.file(join(testDir, 'storage.json')), false, fileService)); + storage = new Storage(new FileStorageDatabase(testDir, false, fileService)); await storage.init(); @@ -76,7 +94,7 @@ suite('Storage', () => { await storage.close(); - storage = new Storage(new FileStorageDatabase(URI.file(join(testDir, 'storage.json')), false, fileService)); + storage = new Storage(new FileStorageDatabase(testDir, false, fileService)); await storage.init(); diff --git a/src/vs/platform/storage/test/common/storageService.test.ts b/src/vs/platform/storage/test/common/storageService.test.ts index 182ff12af03..fd115f627de 100644 --- a/src/vs/platform/storage/test/common/storageService.test.ts +++ b/src/vs/platform/storage/test/common/storageService.test.ts @@ -4,98 +4,102 @@ *--------------------------------------------------------------------------------------------*/ import { strictEqual, ok } from 'assert'; -import { StorageScope, InMemoryStorageService, StorageTarget, IStorageValueChangeEvent, IStorageTargetChangeEvent } from 'vs/platform/storage/common/storage'; +import { StorageScope, InMemoryStorageService, StorageTarget, IStorageValueChangeEvent, IStorageTargetChangeEvent, IStorageService } from 'vs/platform/storage/common/storage'; -suite('StorageService', function () { +export function createSuite(params: { setup: () => Promise, teardown: (service: T) => Promise }): void { - test('Get Data, Integer, Boolean (global, in-memory)', () => { + let storageService: T; + + setup(async () => { + storageService = await params.setup(); + }); + + teardown(() => { + return params.teardown(storageService); + }); + + test('Get Data, Integer, Boolean (global)', () => { storeData(StorageScope.GLOBAL); }); - test('Get Data, Integer, Boolean (workspace, in-memory)', () => { + test('Get Data, Integer, Boolean (workspace)', () => { storeData(StorageScope.WORKSPACE); }); function storeData(scope: StorageScope): void { - const storage = new InMemoryStorageService(); - let storageValueChangeEvents: IStorageValueChangeEvent[] = []; - storage.onDidChangeValue(e => storageValueChangeEvents.push(e)); + storageService.onDidChangeValue(e => storageValueChangeEvents.push(e)); - strictEqual(storage.get('test.get', scope, 'foobar'), 'foobar'); - strictEqual(storage.get('test.get', scope, ''), ''); - strictEqual(storage.getNumber('test.getNumber', scope, 5), 5); - strictEqual(storage.getNumber('test.getNumber', scope, 0), 0); - strictEqual(storage.getBoolean('test.getBoolean', scope, true), true); - strictEqual(storage.getBoolean('test.getBoolean', scope, false), false); + strictEqual(storageService.get('test.get', scope, 'foobar'), 'foobar'); + strictEqual(storageService.get('test.get', scope, ''), ''); + strictEqual(storageService.getNumber('test.getNumber', scope, 5), 5); + strictEqual(storageService.getNumber('test.getNumber', scope, 0), 0); + strictEqual(storageService.getBoolean('test.getBoolean', scope, true), true); + strictEqual(storageService.getBoolean('test.getBoolean', scope, false), false); - storage.store('test.get', 'foobar', scope, StorageTarget.MACHINE); - strictEqual(storage.get('test.get', scope, (undefined)!), 'foobar'); + storageService.store('test.get', 'foobar', scope, StorageTarget.MACHINE); + strictEqual(storageService.get('test.get', scope, (undefined)!), 'foobar'); let storageValueChangeEvent = storageValueChangeEvents.find(e => e.key === 'test.get'); strictEqual(storageValueChangeEvent?.scope, scope); strictEqual(storageValueChangeEvent?.key, 'test.get'); storageValueChangeEvents = []; - storage.store('test.get', '', scope, StorageTarget.MACHINE); - strictEqual(storage.get('test.get', scope, (undefined)!), ''); + storageService.store('test.get', '', scope, StorageTarget.MACHINE); + strictEqual(storageService.get('test.get', scope, (undefined)!), ''); storageValueChangeEvent = storageValueChangeEvents.find(e => e.key === 'test.get'); strictEqual(storageValueChangeEvent!.scope, scope); strictEqual(storageValueChangeEvent!.key, 'test.get'); - storage.store('test.getNumber', 5, scope, StorageTarget.MACHINE); - strictEqual(storage.getNumber('test.getNumber', scope, (undefined)!), 5); + storageService.store('test.getNumber', 5, scope, StorageTarget.MACHINE); + strictEqual(storageService.getNumber('test.getNumber', scope, (undefined)!), 5); - storage.store('test.getNumber', 0, scope, StorageTarget.MACHINE); - strictEqual(storage.getNumber('test.getNumber', scope, (undefined)!), 0); + storageService.store('test.getNumber', 0, scope, StorageTarget.MACHINE); + strictEqual(storageService.getNumber('test.getNumber', scope, (undefined)!), 0); - storage.store('test.getBoolean', true, scope, StorageTarget.MACHINE); - strictEqual(storage.getBoolean('test.getBoolean', scope, (undefined)!), true); + storageService.store('test.getBoolean', true, scope, StorageTarget.MACHINE); + strictEqual(storageService.getBoolean('test.getBoolean', scope, (undefined)!), true); - storage.store('test.getBoolean', false, scope, StorageTarget.MACHINE); - strictEqual(storage.getBoolean('test.getBoolean', scope, (undefined)!), false); + storageService.store('test.getBoolean', false, scope, StorageTarget.MACHINE); + strictEqual(storageService.getBoolean('test.getBoolean', scope, (undefined)!), false); - strictEqual(storage.get('test.getDefault', scope, 'getDefault'), 'getDefault'); - strictEqual(storage.getNumber('test.getNumberDefault', scope, 5), 5); - strictEqual(storage.getBoolean('test.getBooleanDefault', scope, true), true); + strictEqual(storageService.get('test.getDefault', scope, 'getDefault'), 'getDefault'); + strictEqual(storageService.getNumber('test.getNumberDefault', scope, 5), 5); + strictEqual(storageService.getBoolean('test.getBooleanDefault', scope, true), true); } - test('Remove Data (global, in-memory)', () => { + test('Remove Data (global)', () => { removeData(StorageScope.GLOBAL); }); - test('Remove Data (workspace, in-memory)', () => { + test('Remove Data (workspace)', () => { removeData(StorageScope.WORKSPACE); }); function removeData(scope: StorageScope): void { - const storage = new InMemoryStorageService(); - let storageValueChangeEvents: IStorageValueChangeEvent[] = []; - storage.onDidChangeValue(e => storageValueChangeEvents.push(e)); + storageService.onDidChangeValue(e => storageValueChangeEvents.push(e)); - storage.store('test.remove', 'foobar', scope, StorageTarget.MACHINE); - strictEqual('foobar', storage.get('test.remove', scope, (undefined)!)); + storageService.store('test.remove', 'foobar', scope, StorageTarget.MACHINE); + strictEqual('foobar', storageService.get('test.remove', scope, (undefined)!)); - storage.remove('test.remove', scope); - ok(!storage.get('test.remove', scope, (undefined)!)); + storageService.remove('test.remove', scope); + ok(!storageService.get('test.remove', scope, (undefined)!)); let storageValueChangeEvent = storageValueChangeEvents.find(e => e.key === 'test.remove'); strictEqual(storageValueChangeEvent?.scope, scope); strictEqual(storageValueChangeEvent?.key, 'test.remove'); } test('Keys (in-memory)', () => { - const storage = new InMemoryStorageService(); - let storageTargetEvent: IStorageTargetChangeEvent | undefined = undefined; - storage.onDidChangeTarget(e => storageTargetEvent = e); + storageService.onDidChangeTarget(e => storageTargetEvent = e); let storageValueChangeEvent: IStorageValueChangeEvent | undefined = undefined; - storage.onDidChangeValue(e => storageValueChangeEvent = e); + storageService.onDidChangeValue(e => storageValueChangeEvent = e); // Empty for (const scope of [StorageScope.WORKSPACE, StorageScope.GLOBAL]) { for (const target of [StorageTarget.MACHINE, StorageTarget.USER]) { - strictEqual(storage.keys(scope, target).length, 0); + strictEqual(storageService.keys(scope, target).length, 0); } } @@ -105,8 +109,8 @@ suite('StorageService', function () { storageTargetEvent = Object.create(null); storageValueChangeEvent = Object.create(null); - storage.store('test.target1', 'value1', scope, target); - strictEqual(storage.keys(scope, target).length, 1); + storageService.store('test.target1', 'value1', scope, target); + strictEqual(storageService.keys(scope, target).length, 1); strictEqual(storageTargetEvent?.scope, scope); strictEqual(storageValueChangeEvent?.key, 'test.target1'); strictEqual(storageValueChangeEvent?.scope, scope); @@ -115,33 +119,33 @@ suite('StorageService', function () { storageTargetEvent = undefined; storageValueChangeEvent = Object.create(null); - storage.store('test.target1', 'otherValue1', scope, target); - strictEqual(storage.keys(scope, target).length, 1); + storageService.store('test.target1', 'otherValue1', scope, target); + strictEqual(storageService.keys(scope, target).length, 1); strictEqual(storageTargetEvent, undefined); strictEqual(storageValueChangeEvent?.key, 'test.target1'); strictEqual(storageValueChangeEvent?.scope, scope); strictEqual(storageValueChangeEvent?.target, target); - storage.store('test.target2', 'value2', scope, target); - storage.store('test.target3', 'value3', scope, target); + storageService.store('test.target2', 'value2', scope, target); + storageService.store('test.target3', 'value3', scope, target); - strictEqual(storage.keys(scope, target).length, 3); + strictEqual(storageService.keys(scope, target).length, 3); } } // Remove values for (const scope of [StorageScope.WORKSPACE, StorageScope.GLOBAL]) { for (const target of [StorageTarget.MACHINE, StorageTarget.USER]) { - const keysLength = storage.keys(scope, target).length; + const keysLength = storageService.keys(scope, target).length; - storage.store('test.target4', 'value1', scope, target); - strictEqual(storage.keys(scope, target).length, keysLength + 1); + storageService.store('test.target4', 'value1', scope, target); + strictEqual(storageService.keys(scope, target).length, keysLength + 1); storageTargetEvent = Object.create(null); storageValueChangeEvent = Object.create(null); - storage.remove('test.target4', scope); - strictEqual(storage.keys(scope, target).length, keysLength); + storageService.remove('test.target4', scope); + strictEqual(storageService.keys(scope, target).length, keysLength); strictEqual(storageTargetEvent?.scope, scope); strictEqual(storageValueChangeEvent?.key, 'test.target4'); strictEqual(storageValueChangeEvent?.scope, scope); @@ -151,48 +155,55 @@ suite('StorageService', function () { // Remove all for (const scope of [StorageScope.WORKSPACE, StorageScope.GLOBAL]) { for (const target of [StorageTarget.MACHINE, StorageTarget.USER]) { - const keys = storage.keys(scope, target); + const keys = storageService.keys(scope, target); for (const key of keys) { - storage.remove(key, scope); + storageService.remove(key, scope); } - strictEqual(storage.keys(scope, target).length, 0); + strictEqual(storageService.keys(scope, target).length, 0); } } // Adding undefined or null removes value for (const scope of [StorageScope.WORKSPACE, StorageScope.GLOBAL]) { for (const target of [StorageTarget.MACHINE, StorageTarget.USER]) { - storage.store('test.target1', 'value1', scope, target); - strictEqual(storage.keys(scope, target).length, 1); + storageService.store('test.target1', 'value1', scope, target); + strictEqual(storageService.keys(scope, target).length, 1); storageTargetEvent = Object.create(null); - storage.store('test.target1', undefined, scope, target); - strictEqual(storage.keys(scope, target).length, 0); + storageService.store('test.target1', undefined, scope, target); + strictEqual(storageService.keys(scope, target).length, 0); strictEqual(storageTargetEvent?.scope, scope); - storage.store('test.target1', '', scope, target); - strictEqual(storage.keys(scope, target).length, 1); + storageService.store('test.target1', '', scope, target); + strictEqual(storageService.keys(scope, target).length, 1); - storage.store('test.target1', null, scope, target); - strictEqual(storage.keys(scope, target).length, 0); + storageService.store('test.target1', null, scope, target); + strictEqual(storageService.keys(scope, target).length, 0); } } // Target change storageTargetEvent = undefined; - storage.store('test.target5', 'value1', StorageScope.GLOBAL, StorageTarget.MACHINE); + storageService.store('test.target5', 'value1', StorageScope.GLOBAL, StorageTarget.MACHINE); ok(storageTargetEvent); storageTargetEvent = undefined; - storage.store('test.target5', 'value1', StorageScope.GLOBAL, StorageTarget.USER); + storageService.store('test.target5', 'value1', StorageScope.GLOBAL, StorageTarget.USER); ok(storageTargetEvent); storageTargetEvent = undefined; - storage.store('test.target5', 'value1', StorageScope.GLOBAL, StorageTarget.MACHINE); + storageService.store('test.target5', 'value1', StorageScope.GLOBAL, StorageTarget.MACHINE); ok(storageTargetEvent); storageTargetEvent = undefined; - storage.store('test.target5', 'value1', StorageScope.GLOBAL, StorageTarget.MACHINE); + storageService.store('test.target5', 'value1', StorageScope.GLOBAL, StorageTarget.MACHINE); ok(!storageTargetEvent); // no change in target }); +} + +suite('StorageService (in-memory)', function () { + createSuite({ + setup: async () => new InMemoryStorageService(), + teardown: async () => { } + }); }); diff --git a/src/vs/platform/storage/test/node/storageService.test.ts b/src/vs/platform/storage/test/node/storageService.test.ts index fed89b3eda6..ce8eb321aac 100644 --- a/src/vs/platform/storage/test/node/storageService.test.ts +++ b/src/vs/platform/storage/test/node/storageService.test.ts @@ -15,38 +15,46 @@ import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { InMemoryStorageDatabase } from 'vs/base/parts/storage/common/storage'; import { URI } from 'vs/base/common/uri'; import { flakySuite, getRandomTestPath } from 'vs/base/test/node/testUtils'; +import { createSuite } from 'vs/platform/storage/test/common/storageService.test'; -flakySuite('NativeStorageService', function () { +flakySuite('StorageService (native)', function () { + + class StorageTestEnvironmentService extends NativeEnvironmentService { + + constructor(private workspaceStorageFolderPath: URI, private _extensionsPath: string) { + super(parseArgs(process.argv, OPTIONS)); + } + + get workspaceStorageHome(): URI { + return this.workspaceStorageFolderPath; + } + + get extensionsPath(): string { + return this._extensionsPath; + } + } let testDir: string; - setup(() => { - testDir = getRandomTestPath(tmpdir(), 'vsctests', 'storageservice'); + createSuite({ + setup: async () => { + testDir = getRandomTestPath(tmpdir(), 'vsctests', 'storageservice'); - return promises.mkdir(testDir, { recursive: true }); - }); + await promises.mkdir(testDir, { recursive: true }); - teardown(() => { - return rimraf(testDir); + const storageService = new NativeStorageService(new InMemoryStorageDatabase(), new NullLogService(), new StorageTestEnvironmentService(URI.file(testDir), testDir)); + await storageService.initialize({ id: String(Date.now()) }); + + return storageService; + }, + teardown: async storageService => { + await storageService.close(); + + return rimraf(testDir); + } }); test('Migrate Data', async function () { - - class StorageTestEnvironmentService extends NativeEnvironmentService { - - constructor(private workspaceStorageFolderPath: URI, private _extensionsPath: string) { - super(parseArgs(process.argv, OPTIONS)); - } - - get workspaceStorageHome(): URI { - return this.workspaceStorageFolderPath; - } - - get extensionsPath(): string { - return this._extensionsPath; - } - } - const storage = new NativeStorageService(new InMemoryStorageDatabase(), new NullLogService(), new StorageTestEnvironmentService(URI.file(testDir), testDir)); await storage.initialize({ id: String(Date.now()) }); From 3a442c6939b2515fc8109f90886ee6fcae193137 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Sat, 13 Feb 2021 15:40:29 -0800 Subject: [PATCH 121/325] Fix broken markdown cells The editor wants to create a scoped CKS which you can't do with an Overlay --- .../contrib/notebook/browser/view/renderers/markdownCell.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts index 03a42b55550..b45001f687b 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts @@ -308,9 +308,8 @@ export class StatefulMarkdownCell extends Disposable { this.templateData.editorContainer.innerText = ''; // create a special context key service that set the inCompositeEditor-contextkey - const editorContextKeyService = this.contextKeyService.createOverlay([ - [EditorContextKeys.inCompositeEditor.key, true] - ]); + const editorContextKeyService = this.contextKeyService.createScoped(this.templateData.editorPart); + EditorContextKeys.inCompositeEditor.bindTo(editorContextKeyService).set(true); const editorInstaService = this.instantiationService.createChild(new ServiceCollection([IContextKeyService, editorContextKeyService])); this.editor = editorInstaService.createInstance(CodeEditorWidget, this.templateData.editorContainer, { From a699ffaee62010c4634d301da2bbdb7646b8d1da Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Sat, 13 Feb 2021 15:48:37 -0800 Subject: [PATCH 122/325] Reenable notebook smoke test Fix #116535 --- test/smoke/src/areas/notebook/notebook.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/smoke/src/areas/notebook/notebook.test.ts b/test/smoke/src/areas/notebook/notebook.test.ts index 27f8269954b..1d70ee93a89 100644 --- a/test/smoke/src/areas/notebook/notebook.test.ts +++ b/test/smoke/src/areas/notebook/notebook.test.ts @@ -34,7 +34,7 @@ export function setup() { await app.workbench.notebook.stopEditingCell(); }); - it.skip('inserts/edits markdown cell', async function () { + it('inserts/edits markdown cell', async function () { const app = this.app as Application; await app.workbench.notebook.openNotebook(); await app.workbench.notebook.focusNextCell(); From 1f8bb6d33b3095c2152eb5bfd666b3fb41afeaa2 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sun, 14 Feb 2021 12:01:50 +0100 Subject: [PATCH 123/325] storage - change main storage service to support global and workspace storage (stubs) --- .../sharedProcess/sharedProcessMain.ts | 7 +- src/vs/code/electron-main/app.ts | 6 +- src/vs/platform/storage/node/storageIpc.ts | 204 +++++----- src/vs/platform/storage/node/storageMain.ts | 370 ++++++++++++++++++ .../storage/node/storageMainService.ts | 186 ++------- .../platform/storage/node/storageService2.ts | 158 ++++++++ src/vs/platform/windows/common/windows.ts | 3 + .../platform/windows/electron-main/window.ts | 91 +++-- .../electron-browser/desktop.main.ts | 21 +- .../electron-sandbox/desktop.contribution.ts | 6 + .../electron-browser/workbenchTestServices.ts | 1 + 11 files changed, 753 insertions(+), 300 deletions(-) create mode 100644 src/vs/platform/storage/node/storageMain.ts create mode 100644 src/vs/platform/storage/node/storageService2.ts diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 1e4f3c62849..0e4264134c1 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -58,8 +58,8 @@ import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { LoggerService } from 'vs/platform/log/node/loggerService'; import { UserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSyncLog'; import { UserDataAutoSyncService } from 'vs/platform/userDataSync/electron-sandbox/userDataAutoSyncService'; -import { NativeStorageService } from 'vs/platform/storage/node/storageService'; -import { GlobalStorageDatabaseChannelClient } from 'vs/platform/storage/node/storageIpc'; +import { NativeStorageService2 } from 'vs/platform/storage/node/storageService2'; +import { StorageDatabaseChannelClient } from 'vs/platform/storage/node/storageIpc'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { GlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService'; import { UserDataSyncResourceEnablementService } from 'vs/platform/userDataSync/common/userDataSyncResourceEnablementService'; @@ -173,7 +173,8 @@ class SharedProcessMain extends Disposable { await configurationService.initialize(); // Storage - const storageService = new NativeStorageService(new GlobalStorageDatabaseChannelClient(mainProcessService.getChannel('storage')), logService, environmentService); + const storageDatabase = new StorageDatabaseChannelClient(mainProcessService.getChannel('storage'), undefined /* no workspace access for shared process */); + const storageService = new NativeStorageService2(storageDatabase.globalStorage, storageDatabase.workspaceStorage, environmentService); services.set(IStorageService, storageService); await storageService.initialize(); diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index ef4909c7d6b..9646be97a2b 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -59,7 +59,7 @@ import { localize } from 'vs/nls'; import { Schemas } from 'vs/base/common/network'; import { SnapUpdateService } from 'vs/platform/update/electron-main/updateService.snap'; import { IStorageMainService, StorageMainService } from 'vs/platform/storage/node/storageMainService'; -import { GlobalStorageDatabaseChannel } from 'vs/platform/storage/node/storageIpc'; +import { StorageDatabaseChannel } from 'vs/platform/storage/node/storageIpc'; import { BackupMainService } from 'vs/platform/backup/electron-main/backupMainService'; import { IBackupMainService } from 'vs/platform/backup/electron-main/backup'; import { WorkspacesHistoryMainService, IWorkspacesHistoryMainService } from 'vs/platform/workspaces/electron-main/workspacesHistoryMainService'; @@ -582,7 +582,7 @@ export class CodeApplication extends Disposable { // Storage const storageMainService = new StorageMainService(this.logService, this.environmentService); services.set(IStorageMainService, storageMainService); - this.lifecycleMainService.onWillShutdown(e => e.join(storageMainService.close())); + this.lifecycleMainService.onWillShutdown(e => e.join(storageMainService.globalStorage.close())); // Backups const backupMainService = new BackupMainService(this.environmentService, this.configurationService, this.logService); @@ -666,7 +666,7 @@ export class CodeApplication extends Disposable { mainProcessElectronServer.registerChannel('webview', webviewChannel); // Storage (main & shared process) - const storageChannel = this._register(new GlobalStorageDatabaseChannel(this.logService, accessor.get(IStorageMainService))); + const storageChannel = this._register(new StorageDatabaseChannel(this.logService, accessor.get(IStorageMainService))); mainProcessElectronServer.registerChannel('storage', storageChannel); sharedProcessClient.then(client => client.registerChannel('storage', storageChannel)); diff --git a/src/vs/platform/storage/node/storageIpc.ts b/src/vs/platform/storage/node/storageIpc.ts index 67195995c28..e4a95707a57 100644 --- a/src/vs/platform/storage/node/storageIpc.ts +++ b/src/vs/platform/storage/node/storageIpc.ts @@ -3,20 +3,24 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { Emitter, Event } from 'vs/base/common/event'; +import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { Event, Emitter } from 'vs/base/common/event'; -import { IStorageChangeEvent, IStorageMainService } from 'vs/platform/storage/node/storageMainService'; -import { IUpdateRequest, IStorageDatabase, IStorageItemsChangeEvent } from 'vs/base/parts/storage/common/storage'; -import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IStorageDatabase, IStorageItemsChangeEvent, IUpdateRequest } from 'vs/base/parts/storage/common/storage'; import { ILogService } from 'vs/platform/log/common/log'; -import { generateUuid } from 'vs/base/common/uuid'; -import { instanceStorageKey, firstSessionDateStorageKey, lastSessionDateStorageKey, currentSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry'; +import { IStorageChangeEvent, IStorageMain } from 'vs/platform/storage/node/storageMain'; +import { IStorageMainService } from 'vs/platform/storage/node/storageMainService'; +import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; type Key = string; type Value = string; type Item = [Key, Value]; -interface ISerializableUpdateRequest { +interface IWorkspaceArgument { + workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined +} + +interface ISerializableUpdateRequest extends IWorkspaceArgument { insert?: Item[]; delete?: Key[]; } @@ -26,60 +30,34 @@ interface ISerializableItemsChangeEvent { readonly deleted?: Key[]; } -export class GlobalStorageDatabaseChannel extends Disposable implements IServerChannel { +//#region --- Storage Server + +export class StorageDatabaseChannel extends Disposable implements IServerChannel { private static readonly STORAGE_CHANGE_DEBOUNCE_TIME = 100; - private readonly _onDidChangeItems = this._register(new Emitter()); - readonly onDidChangeItems = this._onDidChangeItems.event; - - private readonly whenReady = this.init(); + private readonly _onDidChangeGlobalStorage = this._register(new Emitter()); + private readonly onDidChangeGlobalStorage = this._onDidChangeGlobalStorage.event; constructor( private logService: ILogService, private storageMainService: IStorageMainService ) { super(); + + // Trigger init of global storage directly from ctor + this.withStorageInitialized(undefined); + + this.registerGlobalStorageListeners(); } - private async init(): Promise { - try { - await this.storageMainService.initialize(); - } catch (error) { - this.logService.error(`[storage] init(): Unable to init global storage due to ${error}`); - } + //#region Global Storage Change Events - // Apply global telemetry values as part of the initialization - // These are global across all windows and thereby should be - // written from the main process once. - this.initTelemetry(); - - // Setup storage change listeners - this.registerListeners(); - } - - private initTelemetry(): void { - const instanceId = this.storageMainService.get(instanceStorageKey, undefined); - if (instanceId === undefined) { - this.storageMainService.store(instanceStorageKey, generateUuid()); - } - - const firstSessionDate = this.storageMainService.get(firstSessionDateStorageKey, undefined); - if (firstSessionDate === undefined) { - this.storageMainService.store(firstSessionDateStorageKey, new Date().toUTCString()); - } - - const lastSessionDate = this.storageMainService.get(currentSessionDateStorageKey, undefined); // previous session date was the "current" one at that time - const currentSessionDate = new Date().toUTCString(); // current session date is "now" - this.storageMainService.store(lastSessionDateStorageKey, typeof lastSessionDate === 'undefined' ? null : lastSessionDate); - this.storageMainService.store(currentSessionDateStorageKey, currentSessionDate); - } - - private registerListeners(): void { + private registerGlobalStorageListeners(): void { // Listen for changes in global storage to send to listeners // that are listening. Use a debouncer to reduce IPC traffic. - this._register(Event.debounce(this.storageMainService.onDidChangeStorage, (prev: IStorageChangeEvent[] | undefined, cur: IStorageChangeEvent) => { + this._register(Event.debounce(this.storageMainService.globalStorage.onDidChangeStorage, (prev: IStorageChangeEvent[] | undefined, cur: IStorageChangeEvent) => { if (!prev) { prev = [cur]; } else { @@ -87,18 +65,18 @@ export class GlobalStorageDatabaseChannel extends Disposable implements IServerC } return prev; - }, GlobalStorageDatabaseChannel.STORAGE_CHANGE_DEBOUNCE_TIME)(events => { + }, StorageDatabaseChannel.STORAGE_CHANGE_DEBOUNCE_TIME)(events => { if (events.length) { - this._onDidChangeItems.fire(this.serializeEvents(events)); + this._onDidChangeGlobalStorage.fire(this.serializeGlobalStorageEvents(events)); } })); } - private serializeEvents(events: IStorageChangeEvent[]): ISerializableItemsChangeEvent { + private serializeGlobalStorageEvents(events: IStorageChangeEvent[]): ISerializableItemsChangeEvent { const changed = new Map(); const deleted = new Set(); events.forEach(event => { - const existing = this.storageMainService.get(event.key); + const existing = this.storageMainService.globalStorage.get(event.key); if (typeof existing === 'string') { changed.set(event.key, existing); } else { @@ -114,33 +92,35 @@ export class GlobalStorageDatabaseChannel extends Disposable implements IServerC listen(_: unknown, event: string): Event { switch (event) { - case 'onDidChangeItems': return this.onDidChangeItems; + case 'onDidChangeGlobalStorage': return this.onDidChangeGlobalStorage; } throw new Error(`Event not found: ${event}`); } - async call(_: unknown, command: string, arg?: any): Promise { + //#endregion - // ensure to always wait for ready - await this.whenReady; + async call(_: unknown, command: string, arg: IWorkspaceArgument): Promise { + + // Get storage to be ready + const storage = await this.withStorageInitialized(arg.workspace); // handle call switch (command) { case 'getItems': { - return Array.from(this.storageMainService.items.entries()); + return Array.from(storage.items.entries()); } case 'updateItems': { const items: ISerializableUpdateRequest = arg; if (items.insert) { for (const [key, value] of items.insert) { - this.storageMainService.store(key, value); + storage.store(key, value); } } if (items.delete) { - items.delete.forEach(key => this.storageMainService.remove(key)); + items.delete.forEach(key => storage.remove(key)); } break; @@ -150,44 +130,41 @@ export class GlobalStorageDatabaseChannel extends Disposable implements IServerC throw new Error(`Call not found: ${command}`); } } + + private async withStorageInitialized(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined): Promise { + const storage = workspace ? this.storageMainService.workspaceStorage(workspace) : this.storageMainService.globalStorage; + + try { + await storage.initialize(); + } catch (error) { + this.logService.error(`[storage] init(): Unable to init ${workspace ? 'workspace' : 'global'} storage due to ${error}`); + } + + return storage; + } } -export class GlobalStorageDatabaseChannelClient extends Disposable implements IStorageDatabase { +//#endregion - declare readonly _serviceBrand: undefined; +//#region --- Storage Client - private readonly _onDidChangeItemsExternal = this._register(new Emitter()); - readonly onDidChangeItemsExternal = this._onDidChangeItemsExternal.event; +abstract class BaseStorageDatabase extends Disposable implements IStorageDatabase { - private onDidChangeItemsOnMainListener: IDisposable | undefined; + abstract onDidChangeItemsExternal: Event; - constructor(private channel: IChannel) { + constructor(protected channel: IChannel, private workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined) { super(); - - this.registerListeners(); - } - - private registerListeners(): void { - this.onDidChangeItemsOnMainListener = this.channel.listen('onDidChangeItems')((e: ISerializableItemsChangeEvent) => this.onDidChangeItemsOnMain(e)); - } - - private onDidChangeItemsOnMain(e: ISerializableItemsChangeEvent): void { - if (Array.isArray(e.changed) || Array.isArray(e.deleted)) { - this._onDidChangeItemsExternal.fire({ - changed: e.changed ? new Map(e.changed) : undefined, - deleted: e.deleted ? new Set(e.deleted) : undefined - }); - } } async getItems(): Promise> { - const items: Item[] = await this.channel.call('getItems'); + const serializableRequest: IWorkspaceArgument = { workspace: this.workspace }; + const items: Item[] = await this.channel.call('getItems', serializableRequest); return new Map(items); } updateItems(request: IUpdateRequest): Promise { - const serializableRequest: ISerializableUpdateRequest = Object.create(null); + const serializableRequest: ISerializableUpdateRequest = { workspace: this.workspace }; if (request.insert) { serializableRequest.insert = Array.from(request.insert.entries()); @@ -200,15 +177,66 @@ export class GlobalStorageDatabaseChannelClient extends Disposable implements IS return this.channel.call('updateItems', serializableRequest); } + abstract close(recovery?: () => Map): Promise; +} + +class GlobalStorageDatabase extends BaseStorageDatabase implements IStorageDatabase { + + private readonly _onDidChangeItemsExternal = this._register(new Emitter()); + readonly onDidChangeItemsExternal = this._onDidChangeItemsExternal.event; + + private onDidChangeGlobalStorageListener: IDisposable | undefined; + + constructor(channel: IChannel) { + super(channel, undefined); + + this.registerListeners(); + } + + private registerListeners(): void { + this.onDidChangeGlobalStorageListener = this._register(this.channel.listen('onDidChangeGlobalStorage')((e: ISerializableItemsChangeEvent) => this.onDidChangeGlobalStorage(e))); + } + + private onDidChangeGlobalStorage(e: ISerializableItemsChangeEvent): void { + if (Array.isArray(e.changed) || Array.isArray(e.deleted)) { + this._onDidChangeItemsExternal.fire({ + changed: e.changed ? new Map(e.changed) : undefined, + deleted: e.deleted ? new Set(e.deleted) : undefined + }); + } + } + async close(): Promise { - // when we are about to close, we start to ignore main-side changes since we close anyway - dispose(this.onDidChangeItemsOnMainListener); - } - - dispose(): void { - super.dispose(); - - dispose(this.onDidChangeItemsOnMainListener); + // when we are about to close, we start to ignore global storage changes since we close anyway + dispose(this.onDidChangeGlobalStorageListener); } } + +class WorkspaceStorageDatabase extends BaseStorageDatabase implements IStorageDatabase { + + readonly onDidChangeItemsExternal = Event.None; // unsupported for workspace storage because we only ever write from one window + + constructor(channel: IChannel, workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier) { + super(channel, workspace); + } + + async close(): Promise { + // TODO@bpasero close workspace storage? + } +} + +export class StorageDatabaseChannelClient extends Disposable { + + readonly globalStorage = new GlobalStorageDatabase(this.channel); + readonly workspaceStorage = this.workspace ? new WorkspaceStorageDatabase(this.channel, this.workspace) : undefined; + + constructor( + private channel: IChannel, + private workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined + ) { + super(); + } +} + +//#endregion diff --git a/src/vs/platform/storage/node/storageMain.ts b/src/vs/platform/storage/node/storageMain.ts new file mode 100644 index 00000000000..4fd2e233149 --- /dev/null +++ b/src/vs/platform/storage/node/storageMain.ts @@ -0,0 +1,370 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Event, Emitter } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { ILogService, LogLevel } from 'vs/platform/log/common/log'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { SQLiteStorageDatabase, ISQLiteStorageDatabaseLoggingOptions } from 'vs/base/parts/storage/node/storage'; +import { Storage, IStorage, InMemoryStorageDatabase } from 'vs/base/parts/storage/common/storage'; +import { join } from 'vs/base/common/path'; +import { IS_NEW_KEY } from 'vs/platform/storage/common/storage'; +import { currentSessionDateStorageKey, firstSessionDateStorageKey, instanceStorageKey, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry'; +import { generateUuid } from 'vs/base/common/uuid'; + +/** + * Provides access to global and workspace storage from the + * electron-main side that is the owner of all storage connections. + */ +export interface IStorageMain { + + /** + * Emitted whenever data is updated or deleted. + */ + readonly onDidChangeStorage: Event; + + /** + * Emitted when the storage is about to persist. This is the right time + * to persist data to ensure it is stored before the application shuts + * down. + * + * Note: this event may be fired many times, not only on shutdown to prevent + * loss of state in situations where the shutdown is not sufficient to + * persist the data properly. + */ + readonly onWillSaveState: Event; + + /** + * Access to all cached items of this storage service. + */ + readonly items: Map; + + /** + * Required call to ensure the service can be used. + */ + initialize(): Promise; + + /** + * Retrieve an element stored with the given key from storage. Use + * the provided defaultValue if the element is null or undefined. + */ + get(key: string, fallbackValue: string): string; + get(key: string, fallbackValue?: string): string | undefined; + + /** + * Retrieve an element stored with the given key from storage. Use + * the provided defaultValue if the element is null or undefined. The element + * will be converted to a boolean. + */ + getBoolean(key: string, fallbackValue: boolean): boolean; + getBoolean(key: string, fallbackValue?: boolean): boolean | undefined; + + /** + * Retrieve an element stored with the given key from storage. Use + * the provided defaultValue if the element is null or undefined. The element + * will be converted to a number using parseInt with a base of 10. + */ + getNumber(key: string, fallbackValue: number): number; + getNumber(key: string, fallbackValue?: number): number | undefined; + + /** + * Store a string value under the given key to storage. The value will + * be converted to a string. + */ + store(key: string, value: string | boolean | number | undefined | null): void; + + /** + * Delete an element stored under the provided key from storage. + */ + remove(key: string): void; + + /** + * Close the storage connection. + */ + close(): Promise; +} + +export interface IStorageChangeEvent { + key: string; +} + +export class GlobalStorageMain extends Disposable implements IStorageMain { + + private static readonly STORAGE_NAME = 'state.vscdb'; + + private readonly _onDidChangeStorage = this._register(new Emitter()); + readonly onDidChangeStorage = this._onDidChangeStorage.event; + + private readonly _onWillSaveState = this._register(new Emitter()); + readonly onWillSaveState = this._onWillSaveState.event; + + get items(): Map { return this.storage.items; } + + private storage: IStorage; + + private initializePromise: Promise | undefined; + + constructor( + @ILogService private readonly logService: ILogService, + @IEnvironmentService private readonly environmentService: IEnvironmentService + ) { + super(); + + // Until the storage has been initialized, it can only be in memory + this.storage = new Storage(new InMemoryStorageDatabase()); + } + + private get storagePath(): string { + if (!!this.environmentService.extensionTestsLocationURI) { + return SQLiteStorageDatabase.IN_MEMORY_PATH; // no storage during extension tests! + } + + return join(this.environmentService.globalStorageHome.fsPath, GlobalStorageMain.STORAGE_NAME); + } + + private createLogginOptions(): ISQLiteStorageDatabaseLoggingOptions { + return { + logTrace: (this.logService.getLevel() === LogLevel.Trace) ? msg => this.logService.trace(msg) : undefined, + logError: error => this.logService.error(error) + }; + } + + initialize(): Promise { + if (!this.initializePromise) { + this.initializePromise = this.doInitialize(); + } + + return this.initializePromise; + } + + private async doInitialize(): Promise { + this.storage.dispose(); + this.storage = new Storage(new SQLiteStorageDatabase(this.storagePath, { + logging: this.createLogginOptions() + })); + + this._register(this.storage.onDidChangeStorage(key => this._onDidChangeStorage.fire({ key }))); + + await this.storage.init(); + + // Check to see if this is the first time we are "opening" the application + const firstOpen = this.storage.getBoolean(IS_NEW_KEY); + if (firstOpen === undefined) { + this.storage.set(IS_NEW_KEY, true); + } else if (firstOpen) { + this.storage.set(IS_NEW_KEY, false); + } + + // Apply global telemetry values as part of the initialization + this.storeTelemetryStateOnce(); + } + + private storeTelemetryStateOnce(): void { + const instanceId = this.get(instanceStorageKey, undefined); + if (instanceId === undefined) { + this.store(instanceStorageKey, generateUuid()); + } + + const firstSessionDate = this.get(firstSessionDateStorageKey, undefined); + if (firstSessionDate === undefined) { + this.store(firstSessionDateStorageKey, new Date().toUTCString()); + } + + const lastSessionDate = this.get(currentSessionDateStorageKey, undefined); // previous session date was the "current" one at that time + const currentSessionDate = new Date().toUTCString(); // current session date is "now" + this.store(lastSessionDateStorageKey, typeof lastSessionDate === 'undefined' ? null : lastSessionDate); + this.store(currentSessionDateStorageKey, currentSessionDate); + } + + get(key: string, fallbackValue: string): string; + get(key: string, fallbackValue?: string): string | undefined; + get(key: string, fallbackValue?: string): string | undefined { + return this.storage.get(key, fallbackValue); + } + + getBoolean(key: string, fallbackValue: boolean): boolean; + getBoolean(key: string, fallbackValue?: boolean): boolean | undefined; + getBoolean(key: string, fallbackValue?: boolean): boolean | undefined { + return this.storage.getBoolean(key, fallbackValue); + } + + getNumber(key: string, fallbackValue: number): number; + getNumber(key: string, fallbackValue?: number): number | undefined; + getNumber(key: string, fallbackValue?: number): number | undefined { + return this.storage.getNumber(key, fallbackValue); + } + + store(key: string, value: string | boolean | number | undefined | null): Promise { + return this.storage.set(key, value); + } + + remove(key: string): Promise { + return this.storage.delete(key); + } + + close(): Promise { + + // Signal as event so that clients can still store data + this._onWillSaveState.fire(); + + // Do it + return this.storage.close(); + } +} + +export class WorkspaceStorageMain extends Disposable implements IStorageMain { + + readonly onDidChangeStorage = Event.None; + readonly onWillSaveState = Event.None; + + get items(): Map { return this.storage.items; } + + private storage: IStorage; + + private initializePromise: Promise | undefined; + + constructor( + ) { + super(); + + // Until the storage has been initialized, it can only be in memory + this.storage = new Storage(new InMemoryStorageDatabase()); + } + + async initialize(): Promise { + if (!this.initializePromise) { + this.initializePromise = this.doInitialize(); + } + + return this.initializePromise; + } + + private async doInitialize(): Promise { + // private async initializeWorkspaceStorage(payload: IWorkspaceInitializationPayload): Promise { + + // // Prepare workspace storage folder for DB + // try { + // const result = await this.prepareWorkspaceStorageFolder(payload); + + // const useInMemoryStorage = !!this.environmentService.extensionTestsLocationURI; // no storage during extension tests! + + // // Create workspace storage and initialize + // mark('code/willInitWorkspaceStorage'); + // try { + // const workspaceStorage = this.createWorkspaceStorage( + // useInMemoryStorage ? SQLiteStorageDatabase.IN_MEMORY_PATH : join(result.path, NativeStorageService.WORKSPACE_STORAGE_NAME), + // result.wasCreated ? StorageHint.STORAGE_DOES_NOT_EXIST : undefined + // ); + // await workspaceStorage.init(); + + // // Check to see if this is the first time we are "opening" this workspace + // const firstWorkspaceOpen = workspaceStorage.getBoolean(IS_NEW_KEY); + // if (firstWorkspaceOpen === undefined) { + // workspaceStorage.set(IS_NEW_KEY, result.wasCreated); + // } else if (firstWorkspaceOpen) { + // workspaceStorage.set(IS_NEW_KEY, false); + // } + // } finally { + // mark('code/didInitWorkspaceStorage'); + // } + // } catch (error) { + // this.logService.error(`[storage] initializeWorkspaceStorage(): Unable to init workspace storage due to ${error}`); + // } + // } + + // private createWorkspaceStorage(workspaceStoragePath: string, hint?: StorageHint): IStorage { + + // // Logger for workspace storage + // const workspaceLoggingOptions: ISQLiteStorageDatabaseLoggingOptions = { + // logTrace: (this.logService.getLevel() === LogLevel.Trace) ? msg => this.logService.trace(msg) : undefined, + // logError: error => this.logService.error(error) + // }; + + // // Dispose old (if any) + // dispose(this.workspaceStorage); + // dispose(this.workspaceStorageListener); + + // // Create new + // this.workspaceStoragePath = workspaceStoragePath; + // this.workspaceStorage = new Storage(new SQLiteStorageDatabase(workspaceStoragePath, { logging: workspaceLoggingOptions }), { hint }); + // this.workspaceStorageListener = this.workspaceStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.WORKSPACE, key)); + + // return this.workspaceStorage; + // } + + // private getWorkspaceStorageFolderPath(payload: IWorkspaceInitializationPayload): string { + // return join(this.environmentService.workspaceStorageHome.fsPath, payload.id); // workspace home + workspace id; + // } + + // private async prepareWorkspaceStorageFolder(payload: IWorkspaceInitializationPayload): Promise<{ path: string, wasCreated: boolean }> { + // const workspaceStorageFolderPath = this.getWorkspaceStorageFolderPath(payload); + + // const storageExists = await exists(workspaceStorageFolderPath); + // if (storageExists) { + // return { path: workspaceStorageFolderPath, wasCreated: false }; + // } + + // await promises.mkdir(workspaceStorageFolderPath, { recursive: true }); + + // // Write metadata into folder + // this.ensureWorkspaceStorageFolderMeta(payload); + + // return { path: workspaceStorageFolderPath, wasCreated: true }; + // } + + // private ensureWorkspaceStorageFolderMeta(payload: IWorkspaceInitializationPayload): void { + // let meta: object | undefined = undefined; + // if (isSingleFolderWorkspaceIdentifier(payload)) { + // meta = { folder: payload.uri.toString() }; + // } else if (isWorkspaceIdentifier(payload)) { + // meta = { workspace: payload.configPath.toString() }; + // } + + // if (meta) { + // (async () => { + // try { + // const workspaceStorageMetaPath = join(this.getWorkspaceStorageFolderPath(payload), NativeStorageService.WORKSPACE_META_NAME); + // const storageExists = await exists(workspaceStorageMetaPath); + // if (!storageExists) { + // await writeFile(workspaceStorageMetaPath, JSON.stringify(meta, undefined, 2)); + // } + // } catch (error) { + // this.logService.error(error); + // } + // })(); + // } + // } + } + + get(key: string, fallbackValue: string): string; + get(key: string, fallbackValue?: string): string | undefined; + get(key: string, fallbackValue?: string): string | undefined { + return this.storage.get(key, fallbackValue); + } + + getBoolean(key: string, fallbackValue: boolean): boolean; + getBoolean(key: string, fallbackValue?: boolean): boolean | undefined; + getBoolean(key: string, fallbackValue?: boolean): boolean | undefined { + return this.storage.getBoolean(key, fallbackValue); + } + + getNumber(key: string, fallbackValue: number): number; + getNumber(key: string, fallbackValue?: number): number | undefined; + getNumber(key: string, fallbackValue?: number): number | undefined { + return this.storage.getNumber(key, fallbackValue); + } + + store(key: string, value: string | boolean | number | undefined | null): Promise { + return this.storage.set(key, value); + } + + remove(key: string): Promise { + return this.storage.delete(key); + } + + close(): Promise { + return this.storage.close(); + } +} diff --git a/src/vs/platform/storage/node/storageMainService.ts b/src/vs/platform/storage/node/storageMainService.ts index 0d25d4e6554..0e4920b6fd0 100644 --- a/src/vs/platform/storage/node/storageMainService.ts +++ b/src/vs/platform/storage/node/storageMainService.ts @@ -3,15 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { Event, Emitter } from 'vs/base/common/event'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { ILogService, LogLevel } from 'vs/platform/log/common/log'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { SQLiteStorageDatabase, ISQLiteStorageDatabaseLoggingOptions } from 'vs/base/parts/storage/node/storage'; -import { Storage, IStorage, InMemoryStorageDatabase } from 'vs/base/parts/storage/common/storage'; -import { join } from 'vs/base/common/path'; -import { IS_NEW_KEY } from 'vs/platform/storage/common/storage'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { ILogService } from 'vs/platform/log/common/log'; +import { GlobalStorageMain, IStorageMain, WorkspaceStorageMain } from 'vs/platform/storage/node/storageMain'; +import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; export const IStorageMainService = createDecorator('storageMainService'); @@ -20,172 +16,50 @@ export interface IStorageMainService { readonly _serviceBrand: undefined; /** - * Emitted whenever data is updated or deleted. + * Provides access to the global storage shared across all windows. */ - readonly onDidChangeStorage: Event; + readonly globalStorage: IStorageMain; /** - * Emitted when the storage is about to persist. This is the right time - * to persist data to ensure it is stored before the application shuts - * down. - * - * Note: this event may be fired many times, not only on shutdown to prevent - * loss of state in situations where the shutdown is not sufficient to - * persist the data properly. + * Provides access to the workspace storage specific to a single window. */ - readonly onWillSaveState: Event; - - /** - * Access to all cached items of this storage service. - */ - readonly items: Map; - - /** - * Required call to ensure the service can be used. - */ - initialize(): Promise; - - /** - * Retrieve an element stored with the given key from storage. Use - * the provided defaultValue if the element is null or undefined. - */ - get(key: string, fallbackValue: string): string; - get(key: string, fallbackValue?: string): string | undefined; - - /** - * Retrieve an element stored with the given key from storage. Use - * the provided defaultValue if the element is null or undefined. The element - * will be converted to a boolean. - */ - getBoolean(key: string, fallbackValue: boolean): boolean; - getBoolean(key: string, fallbackValue?: boolean): boolean | undefined; - - /** - * Retrieve an element stored with the given key from storage. Use - * the provided defaultValue if the element is null or undefined. The element - * will be converted to a number using parseInt with a base of 10. - */ - getNumber(key: string, fallbackValue: number): number; - getNumber(key: string, fallbackValue?: number): number | undefined; - - /** - * Store a string value under the given key to storage. The value will - * be converted to a string. - */ - store(key: string, value: string | boolean | number | undefined | null): void; - - /** - * Delete an element stored under the provided key from storage. - */ - remove(key: string): void; + workspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier): IStorageMain; } -export interface IStorageChangeEvent { - key: string; -} - -export class StorageMainService extends Disposable implements IStorageMainService { +export class StorageMainService implements IStorageMainService { declare readonly _serviceBrand: undefined; - private static readonly STORAGE_NAME = 'state.vscdb'; + readonly globalStorage = this.createGlobalStorage(); - private readonly _onDidChangeStorage = this._register(new Emitter()); - readonly onDidChangeStorage = this._onDidChangeStorage.event; - - private readonly _onWillSaveState = this._register(new Emitter()); - readonly onWillSaveState = this._onWillSaveState.event; - - get items(): Map { return this.storage.items; } - - private storage: IStorage; - - private initializePromise: Promise | undefined; + private readonly mapWorkspaceToStorage = new Map(); constructor( @ILogService private readonly logService: ILogService, @IEnvironmentService private readonly environmentService: IEnvironmentService ) { - super(); - - // Until the storage has been initialized, it can only be in memory - this.storage = new Storage(new InMemoryStorageDatabase()); } - private get storagePath(): string { - if (!!this.environmentService.extensionTestsLocationURI) { - return SQLiteStorageDatabase.IN_MEMORY_PATH; // no storage during extension tests! + private createGlobalStorage(): IStorageMain { + const globalStorage = new GlobalStorageMain(this.logService, this.environmentService); + + return globalStorage; + } + + private createWorkspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier): IStorageMain { + const workspaceStorage = new WorkspaceStorageMain(); + // TODO@bpasero lifecycle like global storage? window events? crashes? + + return workspaceStorage; + } + + workspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier): IStorageMain { + let workspaceStorage = this.mapWorkspaceToStorage.get(workspace.id); + if (!workspaceStorage) { + workspaceStorage = this.createWorkspaceStorage(workspace); + this.mapWorkspaceToStorage.set(workspace.id, workspaceStorage); } - return join(this.environmentService.globalStorageHome.fsPath, StorageMainService.STORAGE_NAME); - } - - private createLogginOptions(): ISQLiteStorageDatabaseLoggingOptions { - return { - logTrace: (this.logService.getLevel() === LogLevel.Trace) ? msg => this.logService.trace(msg) : undefined, - logError: error => this.logService.error(error) - }; - } - - initialize(): Promise { - if (!this.initializePromise) { - this.initializePromise = this.doInitialize(); - } - - return this.initializePromise; - } - - private async doInitialize(): Promise { - this.storage.dispose(); - this.storage = new Storage(new SQLiteStorageDatabase(this.storagePath, { - logging: this.createLogginOptions() - })); - - this._register(this.storage.onDidChangeStorage(key => this._onDidChangeStorage.fire({ key }))); - - await this.storage.init(); - - // Check to see if this is the first time we are "opening" the application - const firstOpen = this.storage.getBoolean(IS_NEW_KEY); - if (firstOpen === undefined) { - this.storage.set(IS_NEW_KEY, true); - } else if (firstOpen) { - this.storage.set(IS_NEW_KEY, false); - } - } - - get(key: string, fallbackValue: string): string; - get(key: string, fallbackValue?: string): string | undefined; - get(key: string, fallbackValue?: string): string | undefined { - return this.storage.get(key, fallbackValue); - } - - getBoolean(key: string, fallbackValue: boolean): boolean; - getBoolean(key: string, fallbackValue?: boolean): boolean | undefined; - getBoolean(key: string, fallbackValue?: boolean): boolean | undefined { - return this.storage.getBoolean(key, fallbackValue); - } - - getNumber(key: string, fallbackValue: number): number; - getNumber(key: string, fallbackValue?: number): number | undefined; - getNumber(key: string, fallbackValue?: number): number | undefined { - return this.storage.getNumber(key, fallbackValue); - } - - store(key: string, value: string | boolean | number | undefined | null): Promise { - return this.storage.set(key, value); - } - - remove(key: string): Promise { - return this.storage.delete(key); - } - - close(): Promise { - - // Signal as event so that clients can still store data - this._onWillSaveState.fire(); - - // Do it - return this.storage.close(); + return workspaceStorage; } } diff --git a/src/vs/platform/storage/node/storageService2.ts b/src/vs/platform/storage/node/storageService2.ts new file mode 100644 index 00000000000..e5748a183f0 --- /dev/null +++ b/src/vs/platform/storage/node/storageService2.ts @@ -0,0 +1,158 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; +import { StorageScope, WillSaveStateReason, logStorage, AbstractStorageService } from 'vs/platform/storage/common/storage'; +import { Storage, IStorageDatabase, IStorage } from 'vs/base/parts/storage/common/storage'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces'; +import { assertIsDefined } from 'vs/base/common/types'; +import { Promises, RunOnceScheduler, runWhenIdle } from 'vs/base/common/async'; + +export class NativeStorageService2 extends AbstractStorageService { + + private readonly globalStorage = new Storage(this.globalStorageDatabase); + private readonly workspaceStorage = this.workspaceStorageDatabase ? new Storage(this.workspaceStorageDatabase) : undefined; + + private initializePromise: Promise | undefined; + + private readonly periodicFlushScheduler = this._register(new RunOnceScheduler(() => this.doFlushWhenIdle(), 60000 /* every minute */)); + private runWhenIdleDisposable: IDisposable | undefined = undefined; + + constructor( + private globalStorageDatabase: IStorageDatabase, + private workspaceStorageDatabase: IStorageDatabase | undefined, + @IEnvironmentService private readonly environmentService: IEnvironmentService + ) { + super(); + + this.registerListeners(); + } + + private registerListeners(): void { + this._register(this.globalStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.GLOBAL, key))); + this._register(this.workspaceStorage?.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.WORKSPACE, key)) ?? Disposable.None); + } + + initialize(): Promise { + if (!this.initializePromise) { + this.initializePromise = this.doInitialize(); + } + + return this.initializePromise; + } + + private async doInitialize(): Promise { + + // Init all storage locations + await Promises.settled([ + this.globalStorage.init(), + this.workspaceStorage?.init() ?? Promise.resolve() + ]); + + // On some OS we do not get enough time to persist state on shutdown (e.g. when + // Windows restarts after applying updates). In other cases, VSCode might crash, + // so we periodically save state to reduce the chance of loosing any state. + this.periodicFlushScheduler.schedule(); + } + + get(key: string, scope: StorageScope, fallbackValue: string): string; + get(key: string, scope: StorageScope): string | undefined; + get(key: string, scope: StorageScope, fallbackValue?: string): string | undefined { + return this.getStorage(scope).get(key, fallbackValue); + } + + getBoolean(key: string, scope: StorageScope, fallbackValue: boolean): boolean; + getBoolean(key: string, scope: StorageScope): boolean | undefined; + getBoolean(key: string, scope: StorageScope, fallbackValue?: boolean): boolean | undefined { + return this.getStorage(scope).getBoolean(key, fallbackValue); + } + + getNumber(key: string, scope: StorageScope, fallbackValue: number): number; + getNumber(key: string, scope: StorageScope): number | undefined; + getNumber(key: string, scope: StorageScope, fallbackValue?: number): number | undefined { + return this.getStorage(scope).getNumber(key, fallbackValue); + } + + protected doStore(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): void { + this.getStorage(scope).set(key, value); + } + + protected doRemove(key: string, scope: StorageScope): void { + this.getStorage(scope).delete(key); + } + + private getStorage(scope: StorageScope): IStorage { + return assertIsDefined(scope === StorageScope.GLOBAL ? this.globalStorage : this.workspaceStorage); + } + + protected async doFlush(): Promise { + await Promises.settled([ + this.globalStorage.whenFlushed(), + this.workspaceStorage?.whenFlushed() ?? Promise.resolve() + ]); + } + + private doFlushWhenIdle(): void { + + // Dispose any previous idle runner + dispose(this.runWhenIdleDisposable); + + // Run when idle + this.runWhenIdleDisposable = runWhenIdle(() => { + + // send event to collect state + this.flush(); + + // repeat + this.periodicFlushScheduler.schedule(); + }); + } + + async close(): Promise { + + // Stop periodic scheduler and idle runner as we now collect state normally + this.periodicFlushScheduler.dispose(); + dispose(this.runWhenIdleDisposable); + this.runWhenIdleDisposable = undefined; + + // Signal as event so that clients can still store data + this.emitWillSaveState(WillSaveStateReason.SHUTDOWN); + + // Do it + await Promises.settled([ + this.globalStorage.close(), + this.workspaceStorage?.close() ?? Promise.resolve() + ]); + } + + async logStorage(): Promise { + return logStorage( + this.globalStorage.items, + this.workspaceStorage ? this.workspaceStorage.items : new Map(), + this.environmentService.globalStorageHome.fsPath, + /* this.workspaceStoragePath || */ ''); + } + + async migrate(toWorkspace: IWorkspaceInitializationPayload): Promise { + // if (this.workspaceStoragePath === SQLiteStorageDatabase.IN_MEMORY_PATH) { + // return; // no migration needed if running in memory + // } + + // // Close workspace DB to be able to copy + // await this.getStorage(StorageScope.WORKSPACE).close(); + + // // Prepare new workspace storage folder + // const result = await this.prepareWorkspaceStorageFolder(toWorkspace); + + // const newWorkspaceStoragePath = join(result.path, NativeStorageService.WORKSPACE_STORAGE_NAME); + + // // Copy current storage over to new workspace storage + // await copy(assertIsDefined(this.workspaceStoragePath), newWorkspaceStoragePath, { preserveSymlinks: false }); + + // // Recreate and init workspace storage + // return this.createWorkspaceStorage(newWorkspaceStoragePath).init(); + } +} diff --git a/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts index 2ae70d36bce..3ca7fa2b745 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -114,6 +114,7 @@ export interface IWindowSettings { readonly enableMenuBarMnemonics: boolean; readonly closeWhenEmpty: boolean; readonly clickThroughInactive: boolean; + readonly enableExperimentalMainProcessWorkspaceStorage: boolean; } export function getTitleBarStyle(configurationService: IConfigurationService): 'native' | 'custom' { @@ -253,6 +254,8 @@ export interface INativeWindowConfiguration extends IWindowConfiguration, Native filesToWait?: IPathsToWaitFor; os: IOSConfiguration; + + enableExperimentalMainProcessWorkspaceStorage: boolean; } /** diff --git a/src/vs/platform/windows/electron-main/window.ts b/src/vs/platform/windows/electron-main/window.ts index 7fc86f531bd..2d60e42471c 100644 --- a/src/vs/platform/windows/electron-main/window.ts +++ b/src/vs/platform/windows/electron-main/window.ts @@ -114,9 +114,9 @@ export class CodeWindow extends Disposable implements ICodeWindow { constructor( config: IWindowCreationOptions, @ILogService private readonly logService: ILogService, - @IEnvironmentMainService private readonly environmentService: IEnvironmentMainService, + @IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService, @IFileService private readonly fileService: IFileService, - @IStorageMainService storageService: IStorageMainService, + @IStorageMainService storageMainService: IStorageMainService, @IConfigurationService private readonly configurationService: IConfigurationService, @IThemeMainService private readonly themeMainService: IThemeMainService, @IWorkspacesManagementMainService private readonly workspacesManagementMainService: IWorkspacesManagementMainService, @@ -158,7 +158,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { nativeWindowOpen: true, webviewTag: true, zoomFactor: zoomLevelToZoomFactor(windowConfig?.zoomLevel), - ...this.environmentService.sandbox ? + ...this.environmentMainService.sandbox ? // Sandbox { @@ -181,9 +181,9 @@ export class CodeWindow extends Disposable implements ICodeWindow { // Linux: always // Windows: only when running out of sources, otherwise an icon is set by us on the executable if (isLinux) { - options.icon = join(this.environmentService.appRoot, 'resources/linux/code.png'); - } else if (isWindows && !this.environmentService.isBuilt) { - options.icon = join(this.environmentService.appRoot, 'resources/win32/code_150x150.png'); + options.icon = join(this.environmentMainService.appRoot, 'resources/linux/code.png'); + } else if (isWindows && !this.environmentMainService.isBuilt) { + options.icon = join(this.environmentMainService.appRoot, 'resources/win32/code_150x150.png'); } if (isMacintosh && !this.useNativeFullScreen()) { @@ -217,7 +217,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { this._id = this._win.id; // Open devtools if instructed from command line args - if (this.environmentService.args['open-devtools'] === true) { + if (this.environmentMainService.args['open-devtools'] === true) { this._win.webContents.openDevTools(); } @@ -267,9 +267,9 @@ export class CodeWindow extends Disposable implements ICodeWindow { this.createTouchBar(); // Request handling - this.marketplaceHeadersPromise = resolveMarketplaceHeaders(product.version, this.environmentService, this.fileService, { - get(key) { return storageService.get(key); }, - store(key, value) { storageService.store(key, value); } + this.marketplaceHeadersPromise = resolveMarketplaceHeaders(product.version, this.environmentMainService, this.fileService, { + get: key => storageMainService.globalStorage.get(key), + store: (key, value) => storageMainService.globalStorage.store(key, value) }); // Eventing @@ -535,20 +535,23 @@ export class CodeWindow extends Disposable implements ICodeWindow { }); // Handle configuration changes - this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated())); + this._register(this.configurationService.onDidChangeConfiguration(() => this.onConfigurationUpdated())); // Handle Workspace events this._register(this.workspacesManagementMainService.onUntitledWorkspaceDeleted(e => this.onUntitledWorkspaceDeleted(e))); // Inject headers when requests are incoming const urls = ['https://marketplace.visualstudio.com/*', 'https://*.vsassets.io/*']; - this._win.webContents.session.webRequest.onBeforeSendHeaders({ urls }, (details, cb) => - this.marketplaceHeadersPromise.then(headers => cb({ cancel: false, requestHeaders: Object.assign(details.requestHeaders, headers) }))); + this._win.webContents.session.webRequest.onBeforeSendHeaders({ urls }, async (details, cb) => { + const headers = await this.marketplaceHeadersPromise; + + cb({ cancel: false, requestHeaders: Object.assign(details.requestHeaders, headers) }); + }); } - private onWindowError(error: WindowError.UNRESPONSIVE): void; - private onWindowError(error: WindowError.CRASHED, details: RenderProcessGoneDetails): void; - private onWindowError(error: WindowError, details?: RenderProcessGoneDetails): void { + private async onWindowError(error: WindowError.UNRESPONSIVE): Promise; + private async onWindowError(error: WindowError.CRASHED, details: RenderProcessGoneDetails): Promise; + private async onWindowError(error: WindowError, details?: RenderProcessGoneDetails): Promise { this.logService.error(error === WindowError.CRASHED ? `Main: renderer process crashed (detail: ${details?.reason})` : 'Main: detected unresponsive'); // If we run extension tests from CLI, showing a dialog is not @@ -581,25 +584,25 @@ export class CodeWindow extends Disposable implements ICodeWindow { } // Show Dialog - this.dialogMainService.showMessageBox({ + const result = await this.dialogMainService.showMessageBox({ title: product.nameLong, type: 'warning', buttons: [mnemonicButtonLabel(localize({ key: 'reopen', comment: ['&& denotes a mnemonic'] }, "&&Reopen")), mnemonicButtonLabel(localize({ key: 'wait', comment: ['&& denotes a mnemonic'] }, "&&Keep Waiting")), mnemonicButtonLabel(localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))], message: localize('appStalled', "The window is no longer responding"), detail: localize('appStalledDetail', "You can reopen or close the window or keep waiting."), noLink: true - }, this._win).then(result => { - if (!this._win) { - return; // Return early if the window has been going down already - } + }, this._win); - if (result.response === 0) { - this._win.webContents.forcefullyCrashRenderer(); // Calling reload() immediately after calling this method will force the reload to occur in a new process - this.reload(); - } else if (result.response === 2) { - this.destroyWindow(); - } - }); + if (!this._win) { + return; // Return early if the window has been going down already + } + + if (result.response === 0) { + this._win.webContents.forcefullyCrashRenderer(); // Calling reload() immediately after calling this method will force the reload to occur in a new process + this.reload(); + } else if (result.response === 2) { + this.destroyWindow(); + } } // Crashed @@ -611,24 +614,24 @@ export class CodeWindow extends Disposable implements ICodeWindow { message = localize('appCrashed', "The window has crashed", details?.reason); } - this.dialogMainService.showMessageBox({ + const result = await this.dialogMainService.showMessageBox({ title: product.nameLong, type: 'warning', buttons: [mnemonicButtonLabel(localize({ key: 'reopen', comment: ['&& denotes a mnemonic'] }, "&&Reopen")), mnemonicButtonLabel(localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))], message, detail: localize('appCrashedDetail', "We are sorry for the inconvenience! You can reopen the window to continue where you left off."), noLink: true - }, this._win).then(result => { - if (!this._win) { - return; // Return early if the window has been going down already - } + }, this._win); - if (result.response === 0) { - this.reload(); - } else if (result.response === 1) { - this.destroyWindow(); - } - }); + if (!this._win) { + return; // Return early if the window has been going down already + } + + if (result.response === 0) { + this.reload(); + } else if (result.response === 1) { + this.destroyWindow(); + } } } @@ -747,7 +750,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { // Make window visible if it did not open in N seconds because this indicates an error // Only do this when running out of sources and not when running tests - if (!this.environmentService.isBuilt && !this.environmentService.extensionTestsLocationURI) { + if (!this.environmentMainService.isBuilt && !this.environmentMainService.extensionTestsLocationURI) { this.showTimeoutHandle = setTimeout(() => { if (this._win && !this._win.isVisible() && !this._win.isMinimized()) { this._win.show(); @@ -824,7 +827,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { windowConfiguration.windowId = this._win.id; windowConfiguration.sessionId = `window:${this._win.id}`; windowConfiguration.logLevel = this.logService.getLevel(); - windowConfiguration.logsPath = this.environmentService.logsPath; + windowConfiguration.logsPath = this.environmentMainService.logsPath; // Set zoomlevel const windowConfig = this.configurationService.getValue('window'); @@ -851,13 +854,15 @@ export class CodeWindow extends Disposable implements ICodeWindow { windowConfiguration.perfMarks = getMarks(); // Parts splash - windowConfiguration.partsSplashPath = join(this.environmentService.userDataPath, 'rapid_render.json'); + windowConfiguration.partsSplashPath = join(this.environmentMainService.userDataPath, 'rapid_render.json'); // OS Info windowConfiguration.os = { release: release() }; + windowConfiguration.enableExperimentalMainProcessWorkspaceStorage = !!(windowConfig?.enableExperimentalMainProcessWorkspaceStorage); + // Config (combination of process.argv and window configuration) const environment = parseArgs(process.argv, OPTIONS); const config = Object.assign(environment, windowConfiguration) as unknown as { [key: string]: unknown }; @@ -887,7 +892,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { private doGetUrl(config: object): string { let workbench: string; - if (this.environmentService.sandbox) { + if (this.environmentMainService.sandbox) { workbench = 'vs/code/electron-sandbox/workbench/workbench.html'; } else { workbench = 'vs/code/electron-browser/workbench/workbench.html'; diff --git a/src/vs/workbench/electron-browser/desktop.main.ts b/src/vs/workbench/electron-browser/desktop.main.ts index a6b22ab4def..24a5f7361c7 100644 --- a/src/vs/workbench/electron-browser/desktop.main.ts +++ b/src/vs/workbench/electron-browser/desktop.main.ts @@ -18,11 +18,12 @@ import { NativeWorkbenchEnvironmentService } from 'vs/workbench/services/environ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { INativeWorkbenchConfiguration, INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { IWorkspaceInitializationPayload, reviveIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IWorkspaceInitializationPayload, reviveIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { ILoggerService, ILogService } from 'vs/platform/log/common/log'; import { NativeStorageService } from 'vs/platform/storage/node/storageService'; +import { NativeStorageService2 } from 'vs/platform/storage/node/storageService2'; import { Schemas } from 'vs/base/common/network'; -import { GlobalStorageDatabaseChannelClient } from 'vs/platform/storage/node/storageIpc'; +import { StorageDatabaseChannelClient } from 'vs/platform/storage/node/storageIpc'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { IStorageService } from 'vs/platform/storage/common/storage'; @@ -130,14 +131,14 @@ class DesktopMain extends Disposable { services.logService.trace('workbench configuration', JSON.stringify(this.configuration)); } - private registerListeners(workbench: Workbench, storageService: NativeStorageService): void { + private registerListeners(workbench: Workbench, storageService: NativeStorageService | NativeStorageService2): void { // Workbench Lifecycle this._register(workbench.onShutdown(() => this.dispose())); this._register(workbench.onWillShutdown(event => event.join(storageService.close(), 'join.closeStorage'))); } - private async initServices(): Promise<{ serviceCollection: ServiceCollection, logService: ILogService, storageService: NativeStorageService }> { + private async initServices(): Promise<{ serviceCollection: ServiceCollection, logService: ILogService, storageService: NativeStorageService | NativeStorageService2 }> { const serviceCollection = new ServiceCollection(); @@ -319,9 +320,15 @@ class DesktopMain extends Disposable { } } - private async createStorageService(payload: IWorkspaceInitializationPayload, logService: ILogService, mainProcessService: IMainProcessService): Promise { - const globalStorageDatabase = new GlobalStorageDatabaseChannelClient(mainProcessService.getChannel('storage')); - const storageService = new NativeStorageService(globalStorageDatabase, logService, this.environmentService); + private async createStorageService(payload: IWorkspaceInitializationPayload, logService: ILogService, mainProcessService: IMainProcessService): Promise { + const storageDataBase = new StorageDatabaseChannelClient(mainProcessService.getChannel('storage'), isWorkspaceIdentifier(payload) || isSingleFolderWorkspaceIdentifier(payload) ? payload : undefined); + + let storageService: NativeStorageService | NativeStorageService2; + if (this.configuration.enableExperimentalMainProcessWorkspaceStorage) { + storageService = new NativeStorageService2(storageDataBase.globalStorage, storageDataBase.workspaceStorage, this.environmentService); + } else { + storageService = new NativeStorageService(storageDataBase.globalStorage, logService, this.environmentService); + } try { await storageService.initialize(payload); diff --git a/src/vs/workbench/electron-sandbox/desktop.contribution.ts b/src/vs/workbench/electron-sandbox/desktop.contribution.ts index 299561eb5e1..1b1971fd14e 100644 --- a/src/vs/workbench/electron-sandbox/desktop.contribution.ts +++ b/src/vs/workbench/electron-sandbox/desktop.contribution.ts @@ -273,6 +273,12 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema'; 'scope': ConfigurationScope.APPLICATION, 'description': localize('window.clickThroughInactive', "If enabled, clicking on an inactive window will both activate the window and trigger the element under the mouse if it is clickable. If disabled, clicking anywhere on an inactive window will activate it only and a second click is required on the element."), 'included': isMacintosh + }, + 'window.enableExperimentalMainProcessWorkspaceStorage': { + 'type': 'boolean', + 'default': false, + 'scope': ConfigurationScope.APPLICATION, + 'description': localize('window.localize', "Enables workspace storage access from the main process. Requires a restart to take effect."), } } }); diff --git a/src/vs/workbench/test/electron-browser/workbenchTestServices.ts b/src/vs/workbench/test/electron-browser/workbenchTestServices.ts index f2c26043db4..6dbb50fa818 100644 --- a/src/vs/workbench/test/electron-browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/electron-browser/workbenchTestServices.ts @@ -55,6 +55,7 @@ export const TestWorkbenchConfiguration: INativeWorkbenchConfiguration = { perfMarks: [], colorScheme: { dark: true, highContrast: false }, os: { release: release() }, + enableExperimentalMainProcessWorkspaceStorage: false, ...parseArgs(process.argv, OPTIONS) }; From f49d78c4afc16c4725f439be610986c9a8202b1b Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sun, 14 Feb 2021 12:24:55 +0100 Subject: [PATCH 124/325] storage - fix layers to be able to use native storage service in sandbox --- .../sharedProcess/sharedProcessMain.ts | 4 +- src/vs/code/electron-main/app.ts | 4 +- src/vs/platform/storage/common/storageIpc.ts | 119 +++++++++ .../storage/electron-main/storageIpc.ts | 125 +++++++++ .../{node => electron-main}/storageMain.ts | 0 .../storageMainService.ts | 2 +- .../storageService2.ts | 0 src/vs/platform/storage/node/storageIpc.ts | 242 ------------------ .../platform/windows/electron-main/window.ts | 2 +- .../electron-browser/desktop.main.ts | 10 +- .../electron-sandbox/desktop.main.ts | 91 ++++++- .../sandbox.simpleservices.ts | 19 +- 12 files changed, 335 insertions(+), 283 deletions(-) create mode 100644 src/vs/platform/storage/common/storageIpc.ts create mode 100644 src/vs/platform/storage/electron-main/storageIpc.ts rename src/vs/platform/storage/{node => electron-main}/storageMain.ts (100%) rename src/vs/platform/storage/{node => electron-main}/storageMainService.ts (97%) rename src/vs/platform/storage/{node => electron-sandbox}/storageService2.ts (100%) delete mode 100644 src/vs/platform/storage/node/storageIpc.ts diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 0e4264134c1..22620bc9345 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -58,8 +58,8 @@ import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { LoggerService } from 'vs/platform/log/node/loggerService'; import { UserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSyncLog'; import { UserDataAutoSyncService } from 'vs/platform/userDataSync/electron-sandbox/userDataAutoSyncService'; -import { NativeStorageService2 } from 'vs/platform/storage/node/storageService2'; -import { StorageDatabaseChannelClient } from 'vs/platform/storage/node/storageIpc'; +import { NativeStorageService2 } from 'vs/platform/storage/electron-sandbox/storageService2'; +import { StorageDatabaseChannelClient } from 'vs/platform/storage/common/storageIpc'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { GlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService'; import { UserDataSyncResourceEnablementService } from 'vs/platform/userDataSync/common/userDataSyncResourceEnablementService'; diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 9646be97a2b..918d2fb505d 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -58,8 +58,8 @@ import { joinPath } from 'vs/base/common/resources'; import { localize } from 'vs/nls'; import { Schemas } from 'vs/base/common/network'; import { SnapUpdateService } from 'vs/platform/update/electron-main/updateService.snap'; -import { IStorageMainService, StorageMainService } from 'vs/platform/storage/node/storageMainService'; -import { StorageDatabaseChannel } from 'vs/platform/storage/node/storageIpc'; +import { IStorageMainService, StorageMainService } from 'vs/platform/storage/electron-main/storageMainService'; +import { StorageDatabaseChannel } from 'vs/platform/storage/electron-main/storageIpc'; import { BackupMainService } from 'vs/platform/backup/electron-main/backupMainService'; import { IBackupMainService } from 'vs/platform/backup/electron-main/backup'; import { WorkspacesHistoryMainService, IWorkspacesHistoryMainService } from 'vs/platform/workspaces/electron-main/workspacesHistoryMainService'; diff --git a/src/vs/platform/storage/common/storageIpc.ts b/src/vs/platform/storage/common/storageIpc.ts new file mode 100644 index 00000000000..b885e0ce33a --- /dev/null +++ b/src/vs/platform/storage/common/storageIpc.ts @@ -0,0 +1,119 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Emitter, Event } from 'vs/base/common/event'; +import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { IChannel } from 'vs/base/parts/ipc/common/ipc'; +import { IStorageDatabase, IStorageItemsChangeEvent, IUpdateRequest } from 'vs/base/parts/storage/common/storage'; +import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; + +export type Key = string; +export type Value = string; +export type Item = [Key, Value]; + +export interface IWorkspaceArgument { + workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined +} + +export interface ISerializableUpdateRequest extends IWorkspaceArgument { + insert?: Item[]; + delete?: Key[]; +} + +export interface ISerializableItemsChangeEvent { + readonly changed?: Item[]; + readonly deleted?: Key[]; +} + +abstract class BaseStorageDatabaseClient extends Disposable implements IStorageDatabase { + + abstract onDidChangeItemsExternal: Event; + + constructor(protected channel: IChannel, private workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined) { + super(); + } + + async getItems(): Promise> { + const serializableRequest: IWorkspaceArgument = { workspace: this.workspace }; + const items: Item[] = await this.channel.call('getItems', serializableRequest); + + return new Map(items); + } + + updateItems(request: IUpdateRequest): Promise { + const serializableRequest: ISerializableUpdateRequest = { workspace: this.workspace }; + + if (request.insert) { + serializableRequest.insert = Array.from(request.insert.entries()); + } + + if (request.delete) { + serializableRequest.delete = Array.from(request.delete.values()); + } + + return this.channel.call('updateItems', serializableRequest); + } + + abstract close(recovery?: () => Map): Promise; +} + +class GlobalStorageDatabaseClient extends BaseStorageDatabaseClient implements IStorageDatabase { + + private readonly _onDidChangeItemsExternal = this._register(new Emitter()); + readonly onDidChangeItemsExternal = this._onDidChangeItemsExternal.event; + + private onDidChangeGlobalStorageListener: IDisposable | undefined; + + constructor(channel: IChannel) { + super(channel, undefined); + + this.registerListeners(); + } + + private registerListeners(): void { + this.onDidChangeGlobalStorageListener = this._register(this.channel.listen('onDidChangeGlobalStorage')((e: ISerializableItemsChangeEvent) => this.onDidChangeGlobalStorage(e))); + } + + private onDidChangeGlobalStorage(e: ISerializableItemsChangeEvent): void { + if (Array.isArray(e.changed) || Array.isArray(e.deleted)) { + this._onDidChangeItemsExternal.fire({ + changed: e.changed ? new Map(e.changed) : undefined, + deleted: e.deleted ? new Set(e.deleted) : undefined + }); + } + } + + async close(): Promise { + + // when we are about to close, we start to ignore global storage changes since we close anyway + dispose(this.onDidChangeGlobalStorageListener); + } +} + +class WorkspaceStorageDatabaseClient extends BaseStorageDatabaseClient implements IStorageDatabase { + + readonly onDidChangeItemsExternal = Event.None; // unsupported for workspace storage because we only ever write from one window + + constructor(channel: IChannel, workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier) { + super(channel, workspace); + } + + async close(): Promise { + // TODO@bpasero close workspace storage? + } +} + +export class StorageDatabaseChannelClient extends Disposable { + + readonly globalStorage = new GlobalStorageDatabaseClient(this.channel); + readonly workspaceStorage = this.workspace ? new WorkspaceStorageDatabaseClient(this.channel, this.workspace) : undefined; + + constructor( + private channel: IChannel, + private workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined + ) { + super(); + } +} diff --git a/src/vs/platform/storage/electron-main/storageIpc.ts b/src/vs/platform/storage/electron-main/storageIpc.ts new file mode 100644 index 00000000000..b413e57c1f0 --- /dev/null +++ b/src/vs/platform/storage/electron-main/storageIpc.ts @@ -0,0 +1,125 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Emitter, Event } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { IServerChannel } from 'vs/base/parts/ipc/common/ipc'; +import { ILogService } from 'vs/platform/log/common/log'; +import { ISerializableItemsChangeEvent, ISerializableUpdateRequest, IWorkspaceArgument, Key, Value } from 'vs/platform/storage/common/storageIpc'; +import { IStorageChangeEvent, IStorageMain } from 'vs/platform/storage/electron-main/storageMain'; +import { IStorageMainService } from 'vs/platform/storage/electron-main/storageMainService'; +import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; + +export class StorageDatabaseChannel extends Disposable implements IServerChannel { + + private static readonly STORAGE_CHANGE_DEBOUNCE_TIME = 100; + + private readonly _onDidChangeGlobalStorage = this._register(new Emitter()); + private readonly onDidChangeGlobalStorage = this._onDidChangeGlobalStorage.event; + + constructor( + private logService: ILogService, + private storageMainService: IStorageMainService + ) { + super(); + + // Trigger init of global storage directly from ctor + this.withStorageInitialized(undefined); + + this.registerGlobalStorageListeners(); + } + + //#region Global Storage Change Events + + private registerGlobalStorageListeners(): void { + + // Listen for changes in global storage to send to listeners + // that are listening. Use a debouncer to reduce IPC traffic. + this._register(Event.debounce(this.storageMainService.globalStorage.onDidChangeStorage, (prev: IStorageChangeEvent[] | undefined, cur: IStorageChangeEvent) => { + if (!prev) { + prev = [cur]; + } else { + prev.push(cur); + } + + return prev; + }, StorageDatabaseChannel.STORAGE_CHANGE_DEBOUNCE_TIME)(events => { + if (events.length) { + this._onDidChangeGlobalStorage.fire(this.serializeGlobalStorageEvents(events)); + } + })); + } + + private serializeGlobalStorageEvents(events: IStorageChangeEvent[]): ISerializableItemsChangeEvent { + const changed = new Map(); + const deleted = new Set(); + events.forEach(event => { + const existing = this.storageMainService.globalStorage.get(event.key); + if (typeof existing === 'string') { + changed.set(event.key, existing); + } else { + deleted.add(event.key); + } + }); + + return { + changed: Array.from(changed.entries()), + deleted: Array.from(deleted.values()) + }; + } + + listen(_: unknown, event: string): Event { + switch (event) { + case 'onDidChangeGlobalStorage': return this.onDidChangeGlobalStorage; + } + + throw new Error(`Event not found: ${event}`); + } + + //#endregion + + async call(_: unknown, command: string, arg: IWorkspaceArgument): Promise { + + // Get storage to be ready + const storage = await this.withStorageInitialized(arg.workspace); + + // handle call + switch (command) { + case 'getItems': { + return Array.from(storage.items.entries()); + } + + case 'updateItems': { + const items: ISerializableUpdateRequest = arg; + if (items.insert) { + for (const [key, value] of items.insert) { + storage.store(key, value); + } + } + + if (items.delete) { + items.delete.forEach(key => storage.remove(key)); + } + + break; + } + + default: + throw new Error(`Call not found: ${command}`); + } + } + + private async withStorageInitialized(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined): Promise { + const storage = workspace ? this.storageMainService.workspaceStorage(workspace) : this.storageMainService.globalStorage; + + try { + await storage.initialize(); + } catch (error) { + this.logService.error(`[storage] init(): Unable to init ${workspace ? 'workspace' : 'global'} storage due to ${error}`); + } + + return storage; + } +} diff --git a/src/vs/platform/storage/node/storageMain.ts b/src/vs/platform/storage/electron-main/storageMain.ts similarity index 100% rename from src/vs/platform/storage/node/storageMain.ts rename to src/vs/platform/storage/electron-main/storageMain.ts diff --git a/src/vs/platform/storage/node/storageMainService.ts b/src/vs/platform/storage/electron-main/storageMainService.ts similarity index 97% rename from src/vs/platform/storage/node/storageMainService.ts rename to src/vs/platform/storage/electron-main/storageMainService.ts index 0e4920b6fd0..c9fc335fad4 100644 --- a/src/vs/platform/storage/node/storageMainService.ts +++ b/src/vs/platform/storage/electron-main/storageMainService.ts @@ -6,7 +6,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; -import { GlobalStorageMain, IStorageMain, WorkspaceStorageMain } from 'vs/platform/storage/node/storageMain'; +import { GlobalStorageMain, IStorageMain, WorkspaceStorageMain } from 'vs/platform/storage/electron-main/storageMain'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; export const IStorageMainService = createDecorator('storageMainService'); diff --git a/src/vs/platform/storage/node/storageService2.ts b/src/vs/platform/storage/electron-sandbox/storageService2.ts similarity index 100% rename from src/vs/platform/storage/node/storageService2.ts rename to src/vs/platform/storage/electron-sandbox/storageService2.ts diff --git a/src/vs/platform/storage/node/storageIpc.ts b/src/vs/platform/storage/node/storageIpc.ts deleted file mode 100644 index e4a95707a57..00000000000 --- a/src/vs/platform/storage/node/storageIpc.ts +++ /dev/null @@ -1,242 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; -import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IStorageDatabase, IStorageItemsChangeEvent, IUpdateRequest } from 'vs/base/parts/storage/common/storage'; -import { ILogService } from 'vs/platform/log/common/log'; -import { IStorageChangeEvent, IStorageMain } from 'vs/platform/storage/node/storageMain'; -import { IStorageMainService } from 'vs/platform/storage/node/storageMainService'; -import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; - -type Key = string; -type Value = string; -type Item = [Key, Value]; - -interface IWorkspaceArgument { - workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined -} - -interface ISerializableUpdateRequest extends IWorkspaceArgument { - insert?: Item[]; - delete?: Key[]; -} - -interface ISerializableItemsChangeEvent { - readonly changed?: Item[]; - readonly deleted?: Key[]; -} - -//#region --- Storage Server - -export class StorageDatabaseChannel extends Disposable implements IServerChannel { - - private static readonly STORAGE_CHANGE_DEBOUNCE_TIME = 100; - - private readonly _onDidChangeGlobalStorage = this._register(new Emitter()); - private readonly onDidChangeGlobalStorage = this._onDidChangeGlobalStorage.event; - - constructor( - private logService: ILogService, - private storageMainService: IStorageMainService - ) { - super(); - - // Trigger init of global storage directly from ctor - this.withStorageInitialized(undefined); - - this.registerGlobalStorageListeners(); - } - - //#region Global Storage Change Events - - private registerGlobalStorageListeners(): void { - - // Listen for changes in global storage to send to listeners - // that are listening. Use a debouncer to reduce IPC traffic. - this._register(Event.debounce(this.storageMainService.globalStorage.onDidChangeStorage, (prev: IStorageChangeEvent[] | undefined, cur: IStorageChangeEvent) => { - if (!prev) { - prev = [cur]; - } else { - prev.push(cur); - } - - return prev; - }, StorageDatabaseChannel.STORAGE_CHANGE_DEBOUNCE_TIME)(events => { - if (events.length) { - this._onDidChangeGlobalStorage.fire(this.serializeGlobalStorageEvents(events)); - } - })); - } - - private serializeGlobalStorageEvents(events: IStorageChangeEvent[]): ISerializableItemsChangeEvent { - const changed = new Map(); - const deleted = new Set(); - events.forEach(event => { - const existing = this.storageMainService.globalStorage.get(event.key); - if (typeof existing === 'string') { - changed.set(event.key, existing); - } else { - deleted.add(event.key); - } - }); - - return { - changed: Array.from(changed.entries()), - deleted: Array.from(deleted.values()) - }; - } - - listen(_: unknown, event: string): Event { - switch (event) { - case 'onDidChangeGlobalStorage': return this.onDidChangeGlobalStorage; - } - - throw new Error(`Event not found: ${event}`); - } - - //#endregion - - async call(_: unknown, command: string, arg: IWorkspaceArgument): Promise { - - // Get storage to be ready - const storage = await this.withStorageInitialized(arg.workspace); - - // handle call - switch (command) { - case 'getItems': { - return Array.from(storage.items.entries()); - } - - case 'updateItems': { - const items: ISerializableUpdateRequest = arg; - if (items.insert) { - for (const [key, value] of items.insert) { - storage.store(key, value); - } - } - - if (items.delete) { - items.delete.forEach(key => storage.remove(key)); - } - - break; - } - - default: - throw new Error(`Call not found: ${command}`); - } - } - - private async withStorageInitialized(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined): Promise { - const storage = workspace ? this.storageMainService.workspaceStorage(workspace) : this.storageMainService.globalStorage; - - try { - await storage.initialize(); - } catch (error) { - this.logService.error(`[storage] init(): Unable to init ${workspace ? 'workspace' : 'global'} storage due to ${error}`); - } - - return storage; - } -} - -//#endregion - -//#region --- Storage Client - -abstract class BaseStorageDatabase extends Disposable implements IStorageDatabase { - - abstract onDidChangeItemsExternal: Event; - - constructor(protected channel: IChannel, private workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined) { - super(); - } - - async getItems(): Promise> { - const serializableRequest: IWorkspaceArgument = { workspace: this.workspace }; - const items: Item[] = await this.channel.call('getItems', serializableRequest); - - return new Map(items); - } - - updateItems(request: IUpdateRequest): Promise { - const serializableRequest: ISerializableUpdateRequest = { workspace: this.workspace }; - - if (request.insert) { - serializableRequest.insert = Array.from(request.insert.entries()); - } - - if (request.delete) { - serializableRequest.delete = Array.from(request.delete.values()); - } - - return this.channel.call('updateItems', serializableRequest); - } - - abstract close(recovery?: () => Map): Promise; -} - -class GlobalStorageDatabase extends BaseStorageDatabase implements IStorageDatabase { - - private readonly _onDidChangeItemsExternal = this._register(new Emitter()); - readonly onDidChangeItemsExternal = this._onDidChangeItemsExternal.event; - - private onDidChangeGlobalStorageListener: IDisposable | undefined; - - constructor(channel: IChannel) { - super(channel, undefined); - - this.registerListeners(); - } - - private registerListeners(): void { - this.onDidChangeGlobalStorageListener = this._register(this.channel.listen('onDidChangeGlobalStorage')((e: ISerializableItemsChangeEvent) => this.onDidChangeGlobalStorage(e))); - } - - private onDidChangeGlobalStorage(e: ISerializableItemsChangeEvent): void { - if (Array.isArray(e.changed) || Array.isArray(e.deleted)) { - this._onDidChangeItemsExternal.fire({ - changed: e.changed ? new Map(e.changed) : undefined, - deleted: e.deleted ? new Set(e.deleted) : undefined - }); - } - } - - async close(): Promise { - - // when we are about to close, we start to ignore global storage changes since we close anyway - dispose(this.onDidChangeGlobalStorageListener); - } -} - -class WorkspaceStorageDatabase extends BaseStorageDatabase implements IStorageDatabase { - - readonly onDidChangeItemsExternal = Event.None; // unsupported for workspace storage because we only ever write from one window - - constructor(channel: IChannel, workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier) { - super(channel, workspace); - } - - async close(): Promise { - // TODO@bpasero close workspace storage? - } -} - -export class StorageDatabaseChannelClient extends Disposable { - - readonly globalStorage = new GlobalStorageDatabase(this.channel); - readonly workspaceStorage = this.workspace ? new WorkspaceStorageDatabase(this.channel, this.workspace) : undefined; - - constructor( - private channel: IChannel, - private workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined - ) { - super(); - } -} - -//#endregion diff --git a/src/vs/platform/windows/electron-main/window.ts b/src/vs/platform/windows/electron-main/window.ts index 2d60e42471c..7f42a6c6ae8 100644 --- a/src/vs/platform/windows/electron-main/window.ts +++ b/src/vs/platform/windows/electron-main/window.ts @@ -32,7 +32,7 @@ import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogMain import { mnemonicButtonLabel } from 'vs/base/common/labels'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; -import { IStorageMainService } from 'vs/platform/storage/node/storageMainService'; +import { IStorageMainService } from 'vs/platform/storage/electron-main/storageMainService'; import { ByteSize, IFileService } from 'vs/platform/files/common/files'; import { FileAccess, Schemas } from 'vs/base/common/network'; import { isLaunchedFromCli } from 'vs/platform/environment/node/argvHelper'; diff --git a/src/vs/workbench/electron-browser/desktop.main.ts b/src/vs/workbench/electron-browser/desktop.main.ts index 24a5f7361c7..8b6823290e0 100644 --- a/src/vs/workbench/electron-browser/desktop.main.ts +++ b/src/vs/workbench/electron-browser/desktop.main.ts @@ -21,9 +21,9 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle import { isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IWorkspaceInitializationPayload, reviveIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { ILoggerService, ILogService } from 'vs/platform/log/common/log'; import { NativeStorageService } from 'vs/platform/storage/node/storageService'; -import { NativeStorageService2 } from 'vs/platform/storage/node/storageService2'; +import { NativeStorageService2 } from 'vs/platform/storage/electron-sandbox/storageService2'; import { Schemas } from 'vs/base/common/network'; -import { StorageDatabaseChannelClient } from 'vs/platform/storage/node/storageIpc'; +import { StorageDatabaseChannelClient } from 'vs/platform/storage/common/storageIpc'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { IStorageService } from 'vs/platform/storage/common/storage'; @@ -321,13 +321,13 @@ class DesktopMain extends Disposable { } private async createStorageService(payload: IWorkspaceInitializationPayload, logService: ILogService, mainProcessService: IMainProcessService): Promise { - const storageDataBase = new StorageDatabaseChannelClient(mainProcessService.getChannel('storage'), isWorkspaceIdentifier(payload) || isSingleFolderWorkspaceIdentifier(payload) ? payload : undefined); + const storageDataBaseClient = new StorageDatabaseChannelClient(mainProcessService.getChannel('storage'), isWorkspaceIdentifier(payload) || isSingleFolderWorkspaceIdentifier(payload) ? payload : undefined); let storageService: NativeStorageService | NativeStorageService2; if (this.configuration.enableExperimentalMainProcessWorkspaceStorage) { - storageService = new NativeStorageService2(storageDataBase.globalStorage, storageDataBase.workspaceStorage, this.environmentService); + storageService = new NativeStorageService2(storageDataBaseClient.globalStorage, storageDataBaseClient.workspaceStorage, this.environmentService); } else { - storageService = new NativeStorageService(storageDataBase.globalStorage, logService, this.environmentService); + storageService = new NativeStorageService(storageDataBaseClient.globalStorage, logService, this.environmentService); } try { diff --git a/src/vs/workbench/electron-sandbox/desktop.main.ts b/src/vs/workbench/electron-sandbox/desktop.main.ts index d72468c610b..a28d6151bf8 100644 --- a/src/vs/workbench/electron-sandbox/desktop.main.ts +++ b/src/vs/workbench/electron-sandbox/desktop.main.ts @@ -9,35 +9,43 @@ import { Workbench } from 'vs/workbench/browser/workbench'; import { NativeWindow } from 'vs/workbench/electron-sandbox/window'; import { setZoomLevel, setZoomFactor, setFullscreen } from 'vs/base/browser/browser'; import { domContentLoaded } from 'vs/base/browser/dom'; +import { onUnexpectedError } from 'vs/base/common/errors'; import { URI } from 'vs/base/common/uri'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { INativeWorkbenchConfiguration, INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { reviveIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { ILogService } from 'vs/platform/log/common/log'; +import { isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IWorkspaceInitializationPayload, reviveIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { ILoggerService, ILogService } from 'vs/platform/log/common/log'; +import { NativeStorageService2 } from 'vs/platform/storage/electron-sandbox/storageService2'; import { Schemas } from 'vs/base/common/network'; +import { StorageDatabaseChannelClient } from 'vs/platform/storage/common/storageIpc'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { Disposable } from 'vs/base/common/lifecycle'; import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services'; +import { RemoteAuthorityResolverService } from 'vs/platform/remote/electron-sandbox/remoteAuthorityResolverService'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; -import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { RemoteAgentService } from 'vs/workbench/services/remote/electron-sandbox/remoteAgentServiceImpl'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { FileService } from 'vs/platform/files/common/fileService'; import { IFileService } from 'vs/platform/files/common/files'; import { RemoteFileSystemProvider } from 'vs/workbench/services/remote/common/remoteAgentFileSystemChannel'; import { ISignService } from 'vs/platform/sign/common/sign'; import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider'; +import { basename } from 'vs/base/common/path'; import { IProductService } from 'vs/platform/product/common/productService'; import product from 'vs/platform/product/common/product'; +import { NativeLogService } from 'vs/workbench/services/log/electron-sandbox/logService'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { NativeHostService } from 'vs/platform/native/electron-sandbox/nativeHostService'; -import { SimpleConfigurationService, simpleFileSystemProvider, SimpleLogService, SimpleSignService, SimpleStorageService, SimpleNativeWorkbenchEnvironmentService, SimpleWorkspaceService } from 'vs/workbench/electron-sandbox/sandbox.simpleservices'; -import { INativeWorkbenchConfiguration, INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; -import { RemoteAuthorityResolverService } from 'vs/platform/remote/electron-sandbox/remoteAuthorityResolverService'; import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; import { UriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentityService'; +import { KeyboardLayoutService } from 'vs/workbench/services/keybinding/electron-sandbox/nativeKeyboardLayout'; +import { IKeyboardLayoutService } from 'vs/platform/keyboardLayout/common/keyboardLayout'; +import { LoggerService } from 'vs/workbench/services/log/electron-sandbox/loggerService'; import { ElectronIPCMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService'; +import { SimpleConfigurationService, simpleFileSystemProvider, SimpleSignService, SimpleNativeWorkbenchEnvironmentService, SimpleWorkspaceService } from 'vs/workbench/electron-sandbox/sandbox.simpleservices'; class DesktopMain extends Disposable { @@ -107,14 +115,14 @@ class DesktopMain extends Disposable { services.logService.trace('workbench configuration', JSON.stringify(this.configuration)); } - private registerListeners(workbench: Workbench, storageService: SimpleStorageService): void { + private registerListeners(workbench: Workbench, storageService: NativeStorageService2): void { // Workbench Lifecycle this._register(workbench.onShutdown(() => this.dispose())); this._register(workbench.onWillShutdown(event => event.join(storageService.close(), 'join.closeStorage'))); } - private async initServices(): Promise<{ serviceCollection: ServiceCollection, logService: ILogService, storageService: SimpleStorageService }> { + private async initServices(): Promise<{ serviceCollection: ServiceCollection, logService: ILogService, storageService: NativeStorageService2 }> { const serviceCollection = new ServiceCollection(); @@ -142,8 +150,12 @@ class DesktopMain extends Disposable { // Product serviceCollection.set(IProductService, this.productService); + // Logger + const loggerService = new LoggerService(mainProcessService); + serviceCollection.set(ILoggerService, loggerService); + // Log - const logService = new SimpleLogService(); + const logService = this._register(new NativeLogService(`renderer${this.configuration.windowId}`, loggerService, mainProcessService, this.environmentService)); serviceCollection.set(ILogService, logService); // Remote @@ -209,6 +221,8 @@ class DesktopMain extends Disposable { fileService.registerProvider(Schemas.vscodeRemote, remoteFileSystemProvider); } + const payload = this.resolveWorkspaceInitializationPayload(); + const services = await Promise.all([ this.createWorkspaceService().then(service => { @@ -221,11 +235,19 @@ class DesktopMain extends Disposable { return service; }), - this.createStorageService().then(service => { + this.createStorageService(payload, mainProcessService).then(service => { // Storage serviceCollection.set(IStorageService, service); + return service; + }), + + this.createKeyboardLayoutService(mainProcessService).then(service => { + + // KeyboardLayout + serviceCollection.set(IKeyboardLayoutService, service); + return service; }) ]); @@ -247,12 +269,57 @@ class DesktopMain extends Disposable { return { serviceCollection, logService, storageService: services[1] }; } + private resolveWorkspaceInitializationPayload(): IWorkspaceInitializationPayload { + let workspaceInitializationPayload: IWorkspaceInitializationPayload | undefined = this.configuration.workspace; + + // Fallback to empty workspace if we have no payload yet. + if (!workspaceInitializationPayload) { + let id: string; + if (this.configuration.backupPath) { + id = basename(this.configuration.backupPath); // we know the backupPath must be a unique path so we leverage its name as workspace ID + } else if (this.environmentService.isExtensionDevelopment) { + id = 'ext-dev'; // extension development window never stores backups and is a singleton + } else { + throw new Error('Unexpected window configuration without backupPath'); + } + + workspaceInitializationPayload = { id }; + } + + return workspaceInitializationPayload; + } + private async createWorkspaceService(): Promise { return new SimpleWorkspaceService(); } - private async createStorageService(): Promise { - return new SimpleStorageService(); + private async createStorageService(payload: IWorkspaceInitializationPayload, mainProcessService: IMainProcessService): Promise { + const storageDataBaseClient = new StorageDatabaseChannelClient(mainProcessService.getChannel('storage'), isWorkspaceIdentifier(payload) || isSingleFolderWorkspaceIdentifier(payload) ? payload : undefined); + const storageService = new NativeStorageService2(storageDataBaseClient.globalStorage, storageDataBaseClient.workspaceStorage, this.environmentService); + + try { + await storageService.initialize(); + + return storageService; + } catch (error) { + onUnexpectedError(error); + + return storageService; + } + } + + private async createKeyboardLayoutService(mainProcessService: IMainProcessService): Promise { + const keyboardLayoutService = new KeyboardLayoutService(mainProcessService); + + try { + await keyboardLayoutService.initialize(); + + return keyboardLayoutService; + } catch (error) { + onUnexpectedError(error); + + return keyboardLayoutService; + } } } diff --git a/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts b/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts index 4a2f05f35f9..7b7312d9575 100644 --- a/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts +++ b/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts @@ -6,7 +6,6 @@ /* eslint-disable code-no-standalone-editor */ /* eslint-disable code-import-patterns */ -import { ConsoleLogger, LogService } from 'vs/platform/log/common/log'; import { ISignService } from 'vs/platform/sign/common/sign'; import { URI } from 'vs/base/common/uri'; import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider'; @@ -15,7 +14,6 @@ import { IAddressProvider } from 'vs/platform/remote/common/remoteAgentConnectio import { ITelemetryData, ITelemetryInfo, ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IExtension } from 'vs/platform/extensions/common/extensions'; import { SimpleConfigurationService as BaseSimpleConfigurationService } from 'vs/editor/standalone/browser/simpleServices'; -import { InMemoryStorageService } from 'vs/platform/storage/common/storage'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IBackupFileService, IResolvedBackup } from 'vs/workbench/services/backup/common/backup'; import { ITextSnapshot } from 'vs/editor/common/model'; @@ -177,13 +175,6 @@ export class SimpleWorkspaceService implements IWorkspaceContextService { //#endregion -//#region Configuration - -export class SimpleStorageService extends InMemoryStorageService { } - -//#endregion - - //#region Configuration export class SimpleConfigurationService extends BaseSimpleConfigurationService implements IWorkbenchConfigurationService { @@ -193,15 +184,7 @@ export class SimpleConfigurationService extends BaseSimpleConfigurationService i //#endregion -//#region Logger - -export class SimpleLogService extends LogService { - - constructor() { - super(new ConsoleLogger()); - } - -} +//#region Signing export class SimpleSignService implements ISignService { From 76fecd9855407c017119b63c1c0672bfe5360294 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sun, 14 Feb 2021 12:45:36 +0100 Subject: [PATCH 125/325] storage - add test for storage main service --- .../electron-main/storageMainService.test.ts | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 src/vs/platform/storage/test/electron-main/storageMainService.test.ts diff --git a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts new file mode 100644 index 00000000000..71ce669617e --- /dev/null +++ b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts @@ -0,0 +1,99 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { promises } from 'fs'; +import { tmpdir } from 'os'; +import { strictEqual } from 'assert'; +import { URI } from 'vs/base/common/uri'; +import { rimraf } from 'vs/base/node/pfs'; +import { flakySuite, getRandomTestPath } from 'vs/base/test/node/testUtils'; +import { OPTIONS, parseArgs } from 'vs/platform/environment/node/argv'; +import { NativeEnvironmentService } from 'vs/platform/environment/node/environmentService'; +import { NullLogService } from 'vs/platform/log/common/log'; +import { IStorageMainService, StorageMainService } from 'vs/platform/storage/electron-main/storageMainService'; +import { instanceStorageKey } from 'vs/platform/telemetry/common/telemetry'; +import { IStorageChangeEvent, IStorageMain } from 'vs/platform/storage/electron-main/storageMain'; +import { generateUuid } from 'vs/base/common/uuid'; +import { isWindows } from 'vs/base/common/platform'; + +flakySuite('StorageMainService (native)', function () { + + class StorageTestEnvironmentService extends NativeEnvironmentService { + + constructor(private globalStorageFolderPath: URI, private _extensionsPath: string) { + super(parseArgs(process.argv, OPTIONS)); + } + + get globalStorageHome(): URI { + return this.globalStorageFolderPath; + } + + get extensionsPath(): string { + return this._extensionsPath; + } + } + + let testDir: string; + let storageMainService: IStorageMainService; + + setup(async () => { + testDir = getRandomTestPath(tmpdir(), 'vsctests', 'storageMainService'); + + await promises.mkdir(testDir, { recursive: true }); + + storageMainService = new StorageMainService(new NullLogService(), new StorageTestEnvironmentService(URI.file(testDir), testDir)); + }); + + teardown(async () => { + await storageMainService.globalStorage.close(); + + return rimraf(testDir); + }); + + async function testStorage(storage: IStorageMain, isGlobal: boolean): Promise { + + // Telemetry: added after init + if (isGlobal) { + strictEqual(storageMainService.globalStorage.items.size, 0); + strictEqual(storageMainService.globalStorage.get(instanceStorageKey), undefined); + await storageMainService.globalStorage.initialize(); + strictEqual(typeof storageMainService.globalStorage.get(instanceStorageKey), 'string'); + } + + let storageChangeEvent: IStorageChangeEvent | undefined = undefined; + const listener = storageMainService.globalStorage.onDidChangeStorage(e => { + storageChangeEvent = e; + }); + + // Basic store/get/remove + const size = storageMainService.globalStorage.items.size; + + storageMainService.globalStorage.store('bar', 'foo'); + strictEqual(storageChangeEvent!.key, 'bar'); + storageMainService.globalStorage.store('barNumber', 55); + storageMainService.globalStorage.store('barBoolean', true); + + strictEqual(storageMainService.globalStorage.get('bar'), 'foo'); + strictEqual(storageMainService.globalStorage.getNumber('barNumber'), 55); + strictEqual(storageMainService.globalStorage.getBoolean('barBoolean'), true); + + strictEqual(storageMainService.globalStorage.items.size, size + 3); + + storageMainService.globalStorage.remove('bar'); + strictEqual(storageMainService.globalStorage.get('bar'), undefined); + + strictEqual(storageMainService.globalStorage.items.size, size + 2); + + listener.dispose(); + } + + test('basics (global)', async function () { + testStorage(storageMainService.globalStorage, true); + }); + + test('basics (workspace)', async function () { + testStorage(storageMainService.workspaceStorage({ id: generateUuid(), uri: URI.file(isWindows ? 'C:\\testWorkspace' : '/testWorkspace') }), false); + }); +}); From a508b135382b435dcf0b5f7a050ed625436d09ab Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sun, 14 Feb 2021 16:23:18 +0100 Subject: [PATCH 126/325] storage - wire in close() --- src/vs/platform/storage/common/storageIpc.ts | 21 +++++++++---------- .../storage/electron-main/storageIpc.ts | 10 +++++++++ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/vs/platform/storage/common/storageIpc.ts b/src/vs/platform/storage/common/storageIpc.ts index b885e0ce33a..8196401c0f4 100644 --- a/src/vs/platform/storage/common/storageIpc.ts +++ b/src/vs/platform/storage/common/storageIpc.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { IStorageDatabase, IStorageItemsChangeEvent, IUpdateRequest } from 'vs/base/parts/storage/common/storage'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; @@ -56,7 +56,9 @@ abstract class BaseStorageDatabaseClient extends Disposable implements IStorageD return this.channel.call('updateItems', serializableRequest); } - abstract close(recovery?: () => Map): Promise; + async close(): Promise { + return this.channel.call('close', { workspace: this.workspace }); + } } class GlobalStorageDatabaseClient extends BaseStorageDatabaseClient implements IStorageDatabase { @@ -64,8 +66,6 @@ class GlobalStorageDatabaseClient extends BaseStorageDatabaseClient implements I private readonly _onDidChangeItemsExternal = this._register(new Emitter()); readonly onDidChangeItemsExternal = this._onDidChangeItemsExternal.event; - private onDidChangeGlobalStorageListener: IDisposable | undefined; - constructor(channel: IChannel) { super(channel, undefined); @@ -73,7 +73,7 @@ class GlobalStorageDatabaseClient extends BaseStorageDatabaseClient implements I } private registerListeners(): void { - this.onDidChangeGlobalStorageListener = this._register(this.channel.listen('onDidChangeGlobalStorage')((e: ISerializableItemsChangeEvent) => this.onDidChangeGlobalStorage(e))); + this._register(this.channel.listen('onDidChangeGlobalStorage')((e: ISerializableItemsChangeEvent) => this.onDidChangeGlobalStorage(e))); } private onDidChangeGlobalStorage(e: ISerializableItemsChangeEvent): void { @@ -87,8 +87,11 @@ class GlobalStorageDatabaseClient extends BaseStorageDatabaseClient implements I async close(): Promise { - // when we are about to close, we start to ignore global storage changes since we close anyway - dispose(this.onDidChangeGlobalStorageListener); + // Remove our listeners on `close` because we are no longer + // interested in change events from the global database + this.dispose(); + + return super.close(); } } @@ -99,10 +102,6 @@ class WorkspaceStorageDatabaseClient extends BaseStorageDatabaseClient implement constructor(channel: IChannel, workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier) { super(channel, workspace); } - - async close(): Promise { - // TODO@bpasero close workspace storage? - } } export class StorageDatabaseChannelClient extends Disposable { diff --git a/src/vs/platform/storage/electron-main/storageIpc.ts b/src/vs/platform/storage/electron-main/storageIpc.ts index b413e57c1f0..6719120089d 100644 --- a/src/vs/platform/storage/electron-main/storageIpc.ts +++ b/src/vs/platform/storage/electron-main/storageIpc.ts @@ -106,6 +106,16 @@ export class StorageDatabaseChannel extends Disposable implements IServerChannel break; } + case 'close': { + if (arg.workspace) { + // Only allow to close workspace storage databases but not + // the global database that is shared across multiple connections + return storage.close(); + } + + break; + } + default: throw new Error(`Call not found: ${command}`); } From 980becda8d52cc341ddf349021bbda0788912b4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Sun, 14 Feb 2021 20:10:24 +0100 Subject: [PATCH 127/325] main rename fixes #116341 --- .devcontainer/cache/build-cache-image.sh | 2 +- .devcontainer/devcontainer.json | 2 +- .github/pull_request_template.md | 2 +- .github/workflows/build-chat.yml | 2 +- .github/workflows/ci.yml | 4 ++-- .github/workflows/devcontainer-cache.yml | 6 +++--- .github/workflows/rich-navigation.yml | 2 +- .vscode/notebooks/inbox.github-issues | 2 +- README.md | 2 +- build/azure-pipelines/distro-build.yml | 8 ++++---- build/azure-pipelines/exploration-build.yml | 4 ++-- build/azure-pipelines/product-build.yml | 2 +- build/azure-pipelines/publish-types/publish-types.yml | 2 +- build/azure-pipelines/publish-types/update-types.ts | 2 +- build/gulpfile.editor.js | 2 +- build/gulpfile.vscode.js | 8 ++++---- build/monaco/README-npm.md | 2 +- product.json | 2 +- scripts/generate-definitelytyped.sh | 2 +- .../test/browser/services/decorationRenderOptions.test.ts | 4 ++-- src/vs/platform/product/common/product.ts | 2 +- src/vs/workbench/common/actions.ts | 2 +- test/ui/tree/public/compressed.json | 6 +++--- 23 files changed, 36 insertions(+), 36 deletions(-) diff --git a/.devcontainer/cache/build-cache-image.sh b/.devcontainer/cache/build-cache-image.sh index 78d0fbfdf0c..42e143d7af4 100755 --- a/.devcontainer/cache/build-cache-image.sh +++ b/.devcontainer/cache/build-cache-image.sh @@ -8,7 +8,7 @@ set -e SCRIPT_PATH="$(cd "$(dirname $0)" && pwd)" CONTAINER_IMAGE_REPOSITORY="$1" -BRANCH="${2:-"master"}" +BRANCH="${2:-"main"}" if [ "${CONTAINER_IMAGE_REPOSITORY}" = "" ]; then echo "Container repository not specified!" diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index cd632e134ef..3b82cd9028d 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -2,7 +2,7 @@ "name": "Code - OSS", // Image contents: https://github.com/microsoft/vscode-dev-containers/blob/master/repository-containers/images/github.com/microsoft/vscode/.devcontainer/base.Dockerfile - "image": "mcr.microsoft.com/vscode/devcontainers/repos/microsoft/vscode:branch-master", + "image": "mcr.microsoft.com/vscode/devcontainers/repos/microsoft/vscode:branch-main", "workspaceMount": "source=${localWorkspaceFolder},target=/home/node/workspace/vscode,type=bind,consistency=cached", "workspaceFolder": "/home/node/workspace/vscode", diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 45f9ee8f340..19314029215 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -2,7 +2,7 @@ * Read our Pull Request guidelines: https://github.com/microsoft/vscode/wiki/How-to-Contribute#pull-requests * Associate an issue with the Pull Request. -* Ensure that the code is up-to-date with the `master` branch. +* Ensure that the code is up-to-date with the `main` branch. * Include a description of the proposed changes and how to test them. --> diff --git a/.github/workflows/build-chat.yml b/.github/workflows/build-chat.yml index f9f146164ba..03f3bd42caf 100644 --- a/.github/workflows/build-chat.yml +++ b/.github/workflows/build-chat.yml @@ -7,7 +7,7 @@ on: types: - completed branches: - - master + - main - release/* jobs: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d53283f0cf4..f1324b59bc0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,11 +3,11 @@ name: CI on: push: branches: - - master + - main - release/* pull_request: branches: - - master + - main - release/* jobs: diff --git a/.github/workflows/devcontainer-cache.yml b/.github/workflows/devcontainer-cache.yml index a250b56cd7a..4670186bdda 100644 --- a/.github/workflows/devcontainer-cache.yml +++ b/.github/workflows/devcontainer-cache.yml @@ -2,9 +2,9 @@ name: VS Code Repo Dev Container Cache Image Generation on: push: - # Currently doing this for master, but could be done for PRs as well + # Currently doing this for main, but could be done for PRs as well branches: - - "master" + - "main" # Only updates to these files result in changes to installed packages, so skip otherwise paths: @@ -35,6 +35,6 @@ jobs: az acr login --name $ACR_REGISTRY_NAME GIT_BRANCH=$(echo "${{ github.ref }}" | grep -oP 'refs/(heads|tags)/\K(.+)') - if [ "$GIT_BRANCH" == "" ]; then GIT_BRANCH=master; fi + if [ "$GIT_BRANCH" == "" ]; then GIT_BRANCH=main; fi .devcontainer/cache/build-cache-image.sh "${{ secrets.CONTAINER_IMAGE_REGISTRY }}/public/vscode/devcontainers/repos/microsoft/vscode" "${GIT_BRANCH}" diff --git a/.github/workflows/rich-navigation.yml b/.github/workflows/rich-navigation.yml index aee0796fa28..71824cab83d 100644 --- a/.github/workflows/rich-navigation.yml +++ b/.github/workflows/rich-navigation.yml @@ -3,7 +3,7 @@ on: pull_request: push: branches: - - master + - main jobs: richnav: diff --git a/.vscode/notebooks/inbox.github-issues b/.vscode/notebooks/inbox.github-issues index f14b59f1483..be0a2609cb2 100644 --- a/.vscode/notebooks/inbox.github-issues +++ b/.vscode/notebooks/inbox.github-issues @@ -30,7 +30,7 @@ { "kind": 1, "language": "markdown", - "value": "New issues or pull requests submitted by the community are initially triaged by an [automatic classification bot](https://github.com/microsoft/vscode-github-triage-actions/tree/master/classifier-deep). Issues that the bot does not correctly triage are then triaged by a team member. The team rotates the inbox tracker on a weekly basis.\n\nA [mirror](https://github.com/JacksonKearl/testissues/issues) of the VS Code issue stream is available with details about how the bot classifies issues, including feature-area classifications and confidence ratings. Per-category confidence thresholds and feature-area ownership data is maintained in [.github/classifier.json](https://github.com/microsoft/vscode/blob/master/.github/classifier.json). \n\n💡 The bot is being run through a GitHub action that runs every 30 minutes. Give the bot the opportunity to classify an issue before doing it manually.\n\n### Inbox Tracking\n\nThe inbox tracker is responsible for the [global inbox](https://github.com/microsoft/vscode/issues?utf8=%E2%9C%93&q=is%3Aopen+no%3Aassignee+-label%3Afeature-request+-label%3Atestplan-item+-label%3Aplan-item) containing all **open issues and pull requests** that\n- are neither **feature requests** nor **test plan items** nor **plan items** and\n- have **no owner assignment**.\n\nThe **inbox tracker** may perform any step described in our [issue triaging documentation](https://github.com/microsoft/vscode/wiki/Issues-Triaging) but its main responsibility is to route issues to the actual feature area owner.\n\nFeature area owners track the **feature area inbox** containing all **open issues and pull requests** that\n- are personally assigned to them and are not assigned to any milestone\n- are labeled with their feature area label and are not assigned to any milestone.\nThis secondary triage may involve any of the steps described in our [issue triaging documentation](https://github.com/microsoft/vscode/wiki/Issues-Triaging) and results in a fully triaged or closed issue.\n\nThe [github triage extension](https://github.com/microsoft/vscode-github-triage-extension) can be used to assist with triaging — it provides a \"Command Palette\"-style list of triaging actions like assignment, labeling, and triggers for various bot actions.", + "value": "New issues or pull requests submitted by the community are initially triaged by an [automatic classification bot](https://github.com/microsoft/vscode-github-triage-actions/tree/master/classifier-deep). Issues that the bot does not correctly triage are then triaged by a team member. The team rotates the inbox tracker on a weekly basis.\n\nA [mirror](https://github.com/JacksonKearl/testissues/issues) of the VS Code issue stream is available with details about how the bot classifies issues, including feature-area classifications and confidence ratings. Per-category confidence thresholds and feature-area ownership data is maintained in [.github/classifier.json](https://github.com/microsoft/vscode/blob/main/.github/classifier.json). \n\n💡 The bot is being run through a GitHub action that runs every 30 minutes. Give the bot the opportunity to classify an issue before doing it manually.\n\n### Inbox Tracking\n\nThe inbox tracker is responsible for the [global inbox](https://github.com/microsoft/vscode/issues?utf8=%E2%9C%93&q=is%3Aopen+no%3Aassignee+-label%3Afeature-request+-label%3Atestplan-item+-label%3Aplan-item) containing all **open issues and pull requests** that\n- are neither **feature requests** nor **test plan items** nor **plan items** and\n- have **no owner assignment**.\n\nThe **inbox tracker** may perform any step described in our [issue triaging documentation](https://github.com/microsoft/vscode/wiki/Issues-Triaging) but its main responsibility is to route issues to the actual feature area owner.\n\nFeature area owners track the **feature area inbox** containing all **open issues and pull requests** that\n- are personally assigned to them and are not assigned to any milestone\n- are labeled with their feature area label and are not assigned to any milestone.\nThis secondary triage may involve any of the steps described in our [issue triaging documentation](https://github.com/microsoft/vscode/wiki/Issues-Triaging) and results in a fully triaged or closed issue.\n\nThe [github triage extension](https://github.com/microsoft/vscode-github-triage-extension) can be used to assist with triaging — it provides a \"Command Palette\"-style list of triaging actions like assignment, labeling, and triggers for various bot actions.", "editable": true }, { diff --git a/README.md b/README.md index ec206f09460..541c6e3773c 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ## The Repository -This repository ("`Code - OSS`") is where we (Microsoft) develop the [Visual Studio Code](https://code.visualstudio.com) product. Not only do we work on code and issues here, we also publish our [roadmap](https://github.com/microsoft/vscode/wiki/Roadmap), [monthly iteration plans](https://github.com/microsoft/vscode/wiki/Iteration-Plans), and our [endgame plans](https://github.com/microsoft/vscode/wiki/Running-the-Endgame). This source code is available to everyone under the standard [MIT license](https://github.com/microsoft/vscode/blob/master/LICENSE.txt). +This repository ("`Code - OSS`") is where we (Microsoft) develop the [Visual Studio Code](https://code.visualstudio.com) product. Not only do we work on code and issues here, we also publish our [roadmap](https://github.com/microsoft/vscode/wiki/Roadmap), [monthly iteration plans](https://github.com/microsoft/vscode/wiki/Iteration-Plans), and our [endgame plans](https://github.com/microsoft/vscode/wiki/Running-the-Endgame). This source code is available to everyone under the standard [MIT license](https://github.com/microsoft/vscode/blob/main/LICENSE.txt). ## Visual Studio Code diff --git a/build/azure-pipelines/distro-build.yml b/build/azure-pipelines/distro-build.yml index 331fbf9675e..22d6983e7f8 100644 --- a/build/azure-pipelines/distro-build.yml +++ b/build/azure-pipelines/distro-build.yml @@ -1,9 +1,9 @@ trigger: branches: - include: ["master", "release/*"] + include: ["main", "release/*"] pr: branches: - include: ["master", "release/*"] + include: ["main", "release/*"] steps: - task: NodeTool@0 @@ -31,8 +31,8 @@ steps: git remote add distro "https://github.com/$VSCODE_MIXIN_REPO.git" git fetch distro - # Push master branch into oss/master - git push distro origin/master:refs/heads/oss/master + # Push main branch into oss/main + git push distro origin/main:refs/heads/oss/main # Push every release branch into oss/release git for-each-ref --format="%(refname:short)" refs/remotes/origin/release/* | sed 's/^origin\/\(.*\)$/\0:refs\/heads\/oss\/\1/' | xargs git push distro diff --git a/build/azure-pipelines/exploration-build.yml b/build/azure-pipelines/exploration-build.yml index 22e2602d0aa..719e6e469cb 100644 --- a/build/azure-pipelines/exploration-build.yml +++ b/build/azure-pipelines/exploration-build.yml @@ -28,9 +28,9 @@ steps: git config user.name "VSCode" git checkout origin/electron-11.x.y - git merge origin/master + git merge origin/main - # Push master branch into exploration branch + # Push main branch into exploration branch git push origin HEAD:electron-11.x.y displayName: Sync & Merge Exploration diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index 4d376246944..011f8d4f7d8 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -5,7 +5,7 @@ schedules: displayName: Mon-Fri at 7:00 branches: include: - - master + - main parameters: - name: VSCODE_QUALITY diff --git a/build/azure-pipelines/publish-types/publish-types.yml b/build/azure-pipelines/publish-types/publish-types.yml index 0e3f4e4daa4..09964dc6ad0 100644 --- a/build/azure-pipelines/publish-types/publish-types.yml +++ b/build/azure-pipelines/publish-types/publish-types.yml @@ -61,7 +61,7 @@ steps: TAG_VERSION=$(git describe --tags `git rev-list --tags --max-count=1`) CHANNEL="G1C14HJ2F" - MESSAGE="DefinitelyTyped/DefinitelyTyped#vscode-types-$TAG_VERSION created. Endgame master, please open this link, examine changes and create a PR:" + MESSAGE="DefinitelyTyped/DefinitelyTyped#vscode-types-$TAG_VERSION created. Endgame champion, please open this link, examine changes and create a PR:" LINK="https://github.com/DefinitelyTyped/DefinitelyTyped/compare/vscode-types-$TAG_VERSION?quick_pull=1&body=Updating%20VS%20Code%20Extension%20API.%20See%20https%3A%2F%2Fgithub.com%2Fmicrosoft%2Fvscode%2Fissues%2F70175%20for%20details." MESSAGE2="[@eamodio, @jrieken, @kmaetzel, @egamma]. Please review and merge PR to publish @types/vscode." diff --git a/build/azure-pipelines/publish-types/update-types.ts b/build/azure-pipelines/publish-types/update-types.ts index bbce67221da..eae002e23a7 100644 --- a/build/azure-pipelines/publish-types/update-types.ts +++ b/build/azure-pipelines/publish-types/update-types.ts @@ -72,7 +72,7 @@ function getNewFileHeader(tag: string) { `/*---------------------------------------------------------------------------------------------`, ` * Copyright (c) Microsoft Corporation. All rights reserved.`, ` * Licensed under the MIT License.`, - ` * See https://github.com/microsoft/vscode/blob/master/LICENSE.txt for license information.`, + ` * See https://github.com/microsoft/vscode/blob/main/LICENSE.txt for license information.`, ` *--------------------------------------------------------------------------------------------*/`, ``, `/**`, diff --git a/build/gulpfile.editor.js b/build/gulpfile.editor.js index 7ef97f15be3..230082e4ad9 100644 --- a/build/gulpfile.editor.js +++ b/build/gulpfile.editor.js @@ -49,7 +49,7 @@ let BUNDLED_FILE_HEADER = [ ' * Copyright (c) Microsoft Corporation. All rights reserved.', ' * Version: ' + headerVersion, ' * Released under the MIT license', - ' * https://github.com/microsoft/vscode/blob/master/LICENSE.txt', + ' * https://github.com/microsoft/vscode/blob/main/LICENSE.txt', ' *-----------------------------------------------------------*/', '' ].join('\n'); diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 33af8a45375..7f52a5d99a2 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -526,7 +526,7 @@ gulp.task(task.define( if (!shouldSetupSettingsSearch()) { const branch = process.env.BUILD_SOURCEBRANCH; - console.log(`Only runs on master and release branches, not ${branch}`); + console.log(`Only runs on main and release branches, not ${branch}`); return; } @@ -552,21 +552,21 @@ gulp.task(task.define( function shouldSetupSettingsSearch() { const branch = process.env.BUILD_SOURCEBRANCH; - return branch && (/\/master$/.test(branch) || branch.indexOf('/release/') >= 0); + return branch && (/\/main$/.test(branch) || branch.indexOf('/release/') >= 0); } function getSettingsSearchBuildId(packageJson) { try { const branch = process.env.BUILD_SOURCEBRANCH; const branchId = branch.indexOf('/release/') >= 0 ? 0 : - /\/master$/.test(branch) ? 1 : + /\/main$/.test(branch) ? 1 : 2; // Some unexpected branch const out = cp.execSync(`git rev-list HEAD --count`); const count = parseInt(out.toString()); // - // 1.25.1, 1,234,567 commits, master = 1250112345671 + // 1.25.1, 1,234,567 commits, main = 1250112345671 return util.versionStringToNumber(packageJson.version) * 1e8 + count * 10 + branchId; } catch (e) { throw new Error('Could not determine build number: ' + e.toString()); diff --git a/build/monaco/README-npm.md b/build/monaco/README-npm.md index ee0ffc6e95c..737e06bbc5c 100644 --- a/build/monaco/README-npm.md +++ b/build/monaco/README-npm.md @@ -11,4 +11,4 @@ a good page describing the code editor's features is [here](https://code.visuals This npm module contains the core editor functionality, as it comes from the [vscode repository](https://github.com/microsoft/vscode). ## License -[MIT](https://github.com/microsoft/vscode/blob/master/LICENSE.txt) +[MIT](https://github.com/microsoft/vscode/blob/main/LICENSE.txt) diff --git a/product.json b/product.json index 47bb865de2e..e9561e59ee2 100644 --- a/product.json +++ b/product.json @@ -5,7 +5,7 @@ "dataFolderName": ".vscode-oss", "win32MutexName": "vscodeoss", "licenseName": "MIT", - "licenseUrl": "https://github.com/microsoft/vscode/blob/master/LICENSE.txt", + "licenseUrl": "https://github.com/microsoft/vscode/blob/main/LICENSE.txt", "win32DirName": "Microsoft Code OSS", "win32NameVersion": "Microsoft Code OSS", "win32RegValueName": "CodeOSS", diff --git a/scripts/generate-definitelytyped.sh b/scripts/generate-definitelytyped.sh index 118401b43cb..1b139ebbf79 100755 --- a/scripts/generate-definitelytyped.sh +++ b/scripts/generate-definitelytyped.sh @@ -14,7 +14,7 @@ header="// Type definitions for Visual Studio Code ${1} /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. - * See https://github.com/microsoft/vscode/blob/master/LICENSE.txt for license information. + * See https://github.com/microsoft/vscode/blob/main/LICENSE.txt for license information. *--------------------------------------------------------------------------------------------*/ /** diff --git a/src/vs/editor/test/browser/services/decorationRenderOptions.test.ts b/src/vs/editor/test/browser/services/decorationRenderOptions.test.ts index 37055a85416..a4286aa63af 100644 --- a/src/vs/editor/test/browser/services/decorationRenderOptions.test.ts +++ b/src/vs/editor/test/browser/services/decorationRenderOptions.test.ts @@ -52,7 +52,7 @@ class TestGlobalStyleSheet extends GlobalStyleSheet { suite('Decoration Render Options', () => { let options: IDecorationRenderOptions = { - gutterIconPath: URI.parse('https://github.com/microsoft/vscode/blob/master/resources/linux/code.png'), + gutterIconPath: URI.parse('https://github.com/microsoft/vscode/blob/main/resources/linux/code.png'), gutterIconSize: 'contain', backgroundColor: 'red', borderColor: 'yellow' @@ -79,7 +79,7 @@ suite('Decoration Render Options', () => { const s = new TestCodeEditorServiceImpl(themeServiceMock, styleSheet); s.registerDecorationType('example', options); const sheet = readStyleSheet(styleSheet); - assert(sheet.indexOf(`{background:url('https://github.com/microsoft/vscode/blob/master/resources/linux/code.png') center center no-repeat;background-size:contain;}`) >= 0); + assert(sheet.indexOf(`{background:url('https://github.com/microsoft/vscode/blob/main/resources/linux/code.png') center center no-repeat;background-size:contain;}`) >= 0); assert(sheet.indexOf(`{background-color:red;border-color:yellow;box-sizing: border-box;}`) >= 0); }); diff --git a/src/vs/platform/product/common/product.ts b/src/vs/platform/product/common/product.ts index 71bb6ae4cd6..2730ee7e8c6 100644 --- a/src/vs/platform/product/common/product.ts +++ b/src/vs/platform/product/common/product.ts @@ -28,7 +28,7 @@ if (isWeb || typeof require === 'undefined' || typeof require.__$__nodeRequire ! urlProtocol: 'code-oss', reportIssueUrl: 'https://github.com/microsoft/vscode/issues/new', licenseName: 'MIT', - licenseUrl: 'https://github.com/microsoft/vscode/blob/master/LICENSE.txt', + licenseUrl: 'https://github.com/microsoft/vscode/blob/main/LICENSE.txt', extensionAllowedProposedApi: [ 'ms-vscode.vscode-js-profile-flame', 'ms-vscode.vscode-js-profile-table', diff --git a/src/vs/workbench/common/actions.ts b/src/vs/workbench/common/actions.ts index dfe61debb2e..4640272f1ae 100644 --- a/src/vs/workbench/common/actions.ts +++ b/src/vs/workbench/common/actions.ts @@ -59,7 +59,7 @@ Registry.add(Extensions.WorkbenchActions, new class implements IWorkbenchActionR // menu item // TODO@Rob slightly weird if-check required because of - // https://github.com/microsoft/vscode/blob/master/src/vs/workbench/contrib/search/electron-browser/search.contribution.ts#L266 + // https://github.com/microsoft/vscode/blob/main/src/vs/workbench/contrib/search/electron-browser/search.contribution.ts#L266 if (descriptor.label) { let idx = alias.indexOf(': '); diff --git a/test/ui/tree/public/compressed.json b/test/ui/tree/public/compressed.json index c0b5d4d7161..939a0a29145 100644 --- a/test/ui/tree/public/compressed.json +++ b/test/ui/tree/public/compressed.json @@ -148,7 +148,7 @@ "children": [ { "element": { - "name": "master" + "name": "main" }, "incompressible": true } @@ -228,7 +228,7 @@ "children": [ { "element": { - "name": "master" + "name": "main" }, "incompressible": true } @@ -15617,4 +15617,4 @@ } ] } -] \ No newline at end of file +] From 23a780dbe731c66630579c5aed5a941c410d6721 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 15 Feb 2021 07:44:43 +0100 Subject: [PATCH 128/325] storage - introduce shared class for storage in main --- src/vs/platform/storage/common/storageIpc.ts | 14 +- .../storage/electron-main/storageIpc.ts | 13 +- .../storage/electron-main/storageMain.ts | 238 +++++++++--------- .../electron-main/storageMainService.ts | 31 ++- .../electron-main/storageMainService.test.ts | 51 ++-- .../platform/workspaces/common/workspaces.ts | 8 +- 6 files changed, 192 insertions(+), 163 deletions(-) diff --git a/src/vs/platform/storage/common/storageIpc.ts b/src/vs/platform/storage/common/storageIpc.ts index 8196401c0f4..cd5550464c6 100644 --- a/src/vs/platform/storage/common/storageIpc.ts +++ b/src/vs/platform/storage/common/storageIpc.ts @@ -7,17 +7,17 @@ import { Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { IStorageDatabase, IStorageItemsChangeEvent, IUpdateRequest } from 'vs/base/parts/storage/common/storage'; -import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { ISerializedWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; export type Key = string; export type Value = string; export type Item = [Key, Value]; -export interface IWorkspaceArgument { - workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined +export interface ISerializableWorkspaceArgument { + workspace: ISerializedWorkspaceIdentifier | undefined } -export interface ISerializableUpdateRequest extends IWorkspaceArgument { +export interface ISerializableUpdateRequest extends ISerializableWorkspaceArgument { insert?: Item[]; delete?: Key[]; } @@ -36,7 +36,7 @@ abstract class BaseStorageDatabaseClient extends Disposable implements IStorageD } async getItems(): Promise> { - const serializableRequest: IWorkspaceArgument = { workspace: this.workspace }; + const serializableRequest: ISerializableWorkspaceArgument = { workspace: this.workspace }; const items: Item[] = await this.channel.call('getItems', serializableRequest); return new Map(items); @@ -57,7 +57,9 @@ abstract class BaseStorageDatabaseClient extends Disposable implements IStorageD } async close(): Promise { - return this.channel.call('close', { workspace: this.workspace }); + const serializableRequest: ISerializableWorkspaceArgument = { workspace: this.workspace }; + + return this.channel.call('close', serializableRequest); } } diff --git a/src/vs/platform/storage/electron-main/storageIpc.ts b/src/vs/platform/storage/electron-main/storageIpc.ts index 6719120089d..7eed5eff59e 100644 --- a/src/vs/platform/storage/electron-main/storageIpc.ts +++ b/src/vs/platform/storage/electron-main/storageIpc.ts @@ -7,10 +7,10 @@ import { Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { IServerChannel } from 'vs/base/parts/ipc/common/ipc'; import { ILogService } from 'vs/platform/log/common/log'; -import { ISerializableItemsChangeEvent, ISerializableUpdateRequest, IWorkspaceArgument, Key, Value } from 'vs/platform/storage/common/storageIpc'; +import { ISerializableItemsChangeEvent, ISerializableUpdateRequest, ISerializableWorkspaceArgument, Key, Value } from 'vs/platform/storage/common/storageIpc'; import { IStorageChangeEvent, IStorageMain } from 'vs/platform/storage/electron-main/storageMain'; import { IStorageMainService } from 'vs/platform/storage/electron-main/storageMainService'; -import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier, reviveIdentifier } from 'vs/platform/workspaces/common/workspaces'; export class StorageDatabaseChannel extends Disposable implements IServerChannel { @@ -80,10 +80,11 @@ export class StorageDatabaseChannel extends Disposable implements IServerChannel //#endregion - async call(_: unknown, command: string, arg: IWorkspaceArgument): Promise { + async call(_: unknown, command: string, arg: ISerializableWorkspaceArgument): Promise { + const workspace = reviveIdentifier(arg.workspace); // Get storage to be ready - const storage = await this.withStorageInitialized(arg.workspace); + const storage = await this.withStorageInitialized(workspace); // handle call switch (command) { @@ -107,7 +108,7 @@ export class StorageDatabaseChannel extends Disposable implements IServerChannel } case 'close': { - if (arg.workspace) { + if (workspace) { // Only allow to close workspace storage databases but not // the global database that is shared across multiple connections return storage.close(); @@ -127,7 +128,7 @@ export class StorageDatabaseChannel extends Disposable implements IServerChannel try { await storage.initialize(); } catch (error) { - this.logService.error(`[storage] init(): Unable to init ${workspace ? 'workspace' : 'global'} storage due to ${error}`); + this.logService.error(`StorageIPC#init: Unable to init ${workspace ? 'workspace' : 'global'} storage due to ${error}`); } return storage; diff --git a/src/vs/platform/storage/electron-main/storageMain.ts b/src/vs/platform/storage/electron-main/storageMain.ts index 4fd2e233149..37df63ece3c 100644 --- a/src/vs/platform/storage/electron-main/storageMain.ts +++ b/src/vs/platform/storage/electron-main/storageMain.ts @@ -8,11 +8,12 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { ILogService, LogLevel } from 'vs/platform/log/common/log'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { SQLiteStorageDatabase, ISQLiteStorageDatabaseLoggingOptions } from 'vs/base/parts/storage/node/storage'; -import { Storage, IStorage, InMemoryStorageDatabase } from 'vs/base/parts/storage/common/storage'; +import { Storage, InMemoryStorageDatabase } from 'vs/base/parts/storage/common/storage'; import { join } from 'vs/base/common/path'; import { IS_NEW_KEY } from 'vs/platform/storage/common/storage'; import { currentSessionDateStorageKey, firstSessionDateStorageKey, instanceStorageKey, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry'; import { generateUuid } from 'vs/base/common/uuid'; +import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; /** * Provides access to global and workspace storage from the @@ -36,6 +37,11 @@ export interface IStorageMain { */ readonly onWillSaveState: Event; + /** + * Emitted when the storage is closed. + */ + readonly onDidCloseStorage: Event; + /** * Access to all cached items of this storage service. */ @@ -90,93 +96,43 @@ export interface IStorageChangeEvent { key: string; } -export class GlobalStorageMain extends Disposable implements IStorageMain { +abstract class BaseStorageMain extends Disposable implements IStorageMain { - private static readonly STORAGE_NAME = 'state.vscdb'; - - private readonly _onDidChangeStorage = this._register(new Emitter()); + protected readonly _onDidChangeStorage = this._register(new Emitter()); readonly onDidChangeStorage = this._onDidChangeStorage.event; - private readonly _onWillSaveState = this._register(new Emitter()); + protected readonly _onWillSaveState = this._register(new Emitter()); readonly onWillSaveState = this._onWillSaveState.event; - get items(): Map { return this.storage.items; } + private readonly _onDidCloseStorage = this._register(new Emitter()); + readonly onDidCloseStorage = this._onDidCloseStorage.event; - private storage: IStorage; + private storage = new Storage(new InMemoryStorageDatabase()); // storage is in-memory until initialized - private initializePromise: Promise | undefined; + private initializePromise: Promise | undefined = undefined; - constructor( - @ILogService private readonly logService: ILogService, - @IEnvironmentService private readonly environmentService: IEnvironmentService - ) { + constructor() { super(); - - // Until the storage has been initialized, it can only be in memory - this.storage = new Storage(new InMemoryStorageDatabase()); - } - - private get storagePath(): string { - if (!!this.environmentService.extensionTestsLocationURI) { - return SQLiteStorageDatabase.IN_MEMORY_PATH; // no storage during extension tests! - } - - return join(this.environmentService.globalStorageHome.fsPath, GlobalStorageMain.STORAGE_NAME); - } - - private createLogginOptions(): ISQLiteStorageDatabaseLoggingOptions { - return { - logTrace: (this.logService.getLevel() === LogLevel.Trace) ? msg => this.logService.trace(msg) : undefined, - logError: error => this.logService.error(error) - }; } initialize(): Promise { if (!this.initializePromise) { - this.initializePromise = this.doInitialize(); + this.initializePromise = (async () => { + const storage = await this.doInitialize(); + + // Replace our in-memory storage with the initialized + // one once that is finished and use it from then on + this.storage.dispose(); + this.storage = storage; + })(); } return this.initializePromise; } - private async doInitialize(): Promise { - this.storage.dispose(); - this.storage = new Storage(new SQLiteStorageDatabase(this.storagePath, { - logging: this.createLogginOptions() - })); + protected abstract doInitialize(): Promise; - this._register(this.storage.onDidChangeStorage(key => this._onDidChangeStorage.fire({ key }))); - - await this.storage.init(); - - // Check to see if this is the first time we are "opening" the application - const firstOpen = this.storage.getBoolean(IS_NEW_KEY); - if (firstOpen === undefined) { - this.storage.set(IS_NEW_KEY, true); - } else if (firstOpen) { - this.storage.set(IS_NEW_KEY, false); - } - - // Apply global telemetry values as part of the initialization - this.storeTelemetryStateOnce(); - } - - private storeTelemetryStateOnce(): void { - const instanceId = this.get(instanceStorageKey, undefined); - if (instanceId === undefined) { - this.store(instanceStorageKey, generateUuid()); - } - - const firstSessionDate = this.get(firstSessionDateStorageKey, undefined); - if (firstSessionDate === undefined) { - this.store(firstSessionDateStorageKey, new Date().toUTCString()); - } - - const lastSessionDate = this.get(currentSessionDateStorageKey, undefined); // previous session date was the "current" one at that time - const currentSessionDate = new Date().toUTCString(); // current session date is "now" - this.store(lastSessionDateStorageKey, typeof lastSessionDate === 'undefined' ? null : lastSessionDate); - this.store(currentSessionDateStorageKey, currentSessionDate); - } + get items(): Map { return this.storage.items; } get(key: string, fallbackValue: string): string; get(key: string, fallbackValue?: string): string | undefined; @@ -204,44 +160,112 @@ export class GlobalStorageMain extends Disposable implements IStorageMain { return this.storage.delete(key); } + async close(): Promise { + + // Propagate to storage lib + await this.storage.close(); + + // Signal as event + this._onDidCloseStorage.fire(); + } +} + +export class GlobalStorageMain extends BaseStorageMain implements IStorageMain { + + private static readonly STORAGE_NAME = 'state.vscdb'; + + constructor( + @ILogService private readonly logService: ILogService, + @IEnvironmentService private readonly environmentService: IEnvironmentService + ) { + super(); + } + + private createLogginOptions(): ISQLiteStorageDatabaseLoggingOptions { + return { + logTrace: (this.logService.getLevel() === LogLevel.Trace) ? msg => this.logService.trace(msg) : undefined, + logError: error => this.logService.error(error) + }; + } + + protected async doInitialize(): Promise { + let storagePath: string; + if (!!this.environmentService.extensionTestsLocationURI) { + storagePath = SQLiteStorageDatabase.IN_MEMORY_PATH; // no storage during extension tests! + } else { + storagePath = join(this.environmentService.globalStorageHome.fsPath, GlobalStorageMain.STORAGE_NAME); + } + + const storage = new Storage(new SQLiteStorageDatabase(storagePath, { + logging: this.createLogginOptions() + })); + + // Re-emit storage changes via event + this._register(storage.onDidChangeStorage(key => this._onDidChangeStorage.fire({ key }))); + + await storage.init(); + + // Check to see if this is the first time we are "opening" the application + const firstOpen = storage.getBoolean(IS_NEW_KEY); + if (firstOpen === undefined) { + storage.set(IS_NEW_KEY, true); + } else if (firstOpen) { + storage.set(IS_NEW_KEY, false); + } + + // Apply global telemetry values as part of the initialization + this.updateTelemetryState(storage); + + return storage; + } + + private updateTelemetryState(storage: Storage): void { + + // Instance UUID (once) + const instanceId = storage.get(instanceStorageKey, undefined); + if (instanceId === undefined) { + storage.set(instanceStorageKey, generateUuid()); + } + + // First session date (once) + const firstSessionDate = storage.get(firstSessionDateStorageKey, undefined); + if (firstSessionDate === undefined) { + storage.set(firstSessionDateStorageKey, new Date().toUTCString()); + } + + // Last / current session (always) + // previous session date was the "current" one at that time + // current session date is "now" + const lastSessionDate = storage.get(currentSessionDateStorageKey, undefined); + const currentSessionDate = new Date().toUTCString(); + storage.set(lastSessionDateStorageKey, typeof lastSessionDate === 'undefined' ? null : lastSessionDate); + storage.set(currentSessionDateStorageKey, currentSessionDate); + } + close(): Promise { // Signal as event so that clients can still store data this._onWillSaveState.fire(); // Do it - return this.storage.close(); + return super.close(); } } -export class WorkspaceStorageMain extends Disposable implements IStorageMain { +export class WorkspaceStorageMain extends BaseStorageMain implements IStorageMain { - readonly onDidChangeStorage = Event.None; - readonly onWillSaveState = Event.None; - - get items(): Map { return this.storage.items; } - - private storage: IStorage; - - private initializePromise: Promise | undefined; - - constructor( - ) { + constructor(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier) { super(); - - // Until the storage has been initialized, it can only be in memory - this.storage = new Storage(new InMemoryStorageDatabase()); } - async initialize(): Promise { - if (!this.initializePromise) { - this.initializePromise = this.doInitialize(); - } + protected async doInitialize(): Promise { + const storage = new Storage(new InMemoryStorageDatabase()); - return this.initializePromise; - } + // Re-emit storage changes via event + this._register(storage.onDidChangeStorage(key => this._onDidChangeStorage.fire({ key }))); + + return storage; - private async doInitialize(): Promise { // private async initializeWorkspaceStorage(payload: IWorkspaceInitializationPayload): Promise { // // Prepare workspace storage folder for DB @@ -337,34 +361,4 @@ export class WorkspaceStorageMain extends Disposable implements IStorageMain { // } // } } - - get(key: string, fallbackValue: string): string; - get(key: string, fallbackValue?: string): string | undefined; - get(key: string, fallbackValue?: string): string | undefined { - return this.storage.get(key, fallbackValue); - } - - getBoolean(key: string, fallbackValue: boolean): boolean; - getBoolean(key: string, fallbackValue?: boolean): boolean | undefined; - getBoolean(key: string, fallbackValue?: boolean): boolean | undefined { - return this.storage.getBoolean(key, fallbackValue); - } - - getNumber(key: string, fallbackValue: number): number; - getNumber(key: string, fallbackValue?: number): number | undefined; - getNumber(key: string, fallbackValue?: number): number | undefined { - return this.storage.getNumber(key, fallbackValue); - } - - store(key: string, value: string | boolean | number | undefined | null): Promise { - return this.storage.set(key, value); - } - - remove(key: string): Promise { - return this.storage.delete(key); - } - - close(): Promise { - return this.storage.close(); - } } diff --git a/src/vs/platform/storage/electron-main/storageMainService.ts b/src/vs/platform/storage/electron-main/storageMainService.ts index c9fc335fad4..5647a4ea36c 100644 --- a/src/vs/platform/storage/electron-main/storageMainService.ts +++ b/src/vs/platform/storage/electron-main/storageMainService.ts @@ -3,11 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { once } from 'vs/base/common/functional'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; import { GlobalStorageMain, IStorageMain, WorkspaceStorageMain } from 'vs/platform/storage/electron-main/storageMain'; -import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { ISingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; export const IStorageMainService = createDecorator('storageMainService'); @@ -30,25 +31,31 @@ export class StorageMainService implements IStorageMainService { declare readonly _serviceBrand: undefined; - readonly globalStorage = this.createGlobalStorage(); - - private readonly mapWorkspaceToStorage = new Map(); - constructor( @ILogService private readonly logService: ILogService, @IEnvironmentService private readonly environmentService: IEnvironmentService ) { } + //#region Global Storage + + readonly globalStorage = this.createGlobalStorage(); + private createGlobalStorage(): IStorageMain { const globalStorage = new GlobalStorageMain(this.logService, this.environmentService); return globalStorage; } + //#endregion + + + //#region Workspace Storage + + private readonly mapWorkspaceToStorage = new Map(); + private createWorkspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier): IStorageMain { - const workspaceStorage = new WorkspaceStorageMain(); - // TODO@bpasero lifecycle like global storage? window events? crashes? + const workspaceStorage = new WorkspaceStorageMain(workspace); return workspaceStorage; } @@ -56,10 +63,20 @@ export class StorageMainService implements IStorageMainService { workspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier): IStorageMain { let workspaceStorage = this.mapWorkspaceToStorage.get(workspace.id); if (!workspaceStorage) { + this.logService.info(`StorageMainService: creating workspace storage (${isWorkspaceIdentifier(workspace) ? workspace.configPath : workspace.uri})`); + workspaceStorage = this.createWorkspaceStorage(workspace); this.mapWorkspaceToStorage.set(workspace.id, workspaceStorage); + + once(workspaceStorage.onDidCloseStorage)(() => { + this.logService.info(`StorageMainService: closed workspace storage (${isWorkspaceIdentifier(workspace) ? workspace.configPath : workspace.uri})`); + + this.mapWorkspaceToStorage.delete(workspace.id); + }); } return workspaceStorage; } + + //#endregion } diff --git a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts index 71ce669617e..0383a7264f5 100644 --- a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts +++ b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts @@ -56,44 +56,53 @@ flakySuite('StorageMainService (native)', function () { // Telemetry: added after init if (isGlobal) { - strictEqual(storageMainService.globalStorage.items.size, 0); - strictEqual(storageMainService.globalStorage.get(instanceStorageKey), undefined); - await storageMainService.globalStorage.initialize(); - strictEqual(typeof storageMainService.globalStorage.get(instanceStorageKey), 'string'); + strictEqual(storage.items.size, 0); + strictEqual(storage.get(instanceStorageKey), undefined); + await storage.initialize(); + strictEqual(typeof storage.get(instanceStorageKey), 'string'); } let storageChangeEvent: IStorageChangeEvent | undefined = undefined; - const listener = storageMainService.globalStorage.onDidChangeStorage(e => { + const storageChangeListener = storage.onDidChangeStorage(e => { storageChangeEvent = e; }); + let storageDidClose = false; + const storageCloseListener = storage.onDidCloseStorage(() => storageDidClose = true); + // Basic store/get/remove - const size = storageMainService.globalStorage.items.size; + const size = storage.items.size; - storageMainService.globalStorage.store('bar', 'foo'); + storage.store('bar', 'foo'); strictEqual(storageChangeEvent!.key, 'bar'); - storageMainService.globalStorage.store('barNumber', 55); - storageMainService.globalStorage.store('barBoolean', true); + storage.store('barNumber', 55); + storage.store('barBoolean', true); - strictEqual(storageMainService.globalStorage.get('bar'), 'foo'); - strictEqual(storageMainService.globalStorage.getNumber('barNumber'), 55); - strictEqual(storageMainService.globalStorage.getBoolean('barBoolean'), true); + strictEqual(storage.get('bar'), 'foo'); + strictEqual(storage.getNumber('barNumber'), 55); + strictEqual(storage.getBoolean('barBoolean'), true); - strictEqual(storageMainService.globalStorage.items.size, size + 3); + strictEqual(storage.items.size, size + 3); - storageMainService.globalStorage.remove('bar'); - strictEqual(storageMainService.globalStorage.get('bar'), undefined); + storage.remove('bar'); + strictEqual(storage.get('bar'), undefined); - strictEqual(storageMainService.globalStorage.items.size, size + 2); + strictEqual(storage.items.size, size + 2); - listener.dispose(); + // Close + await storage.close(); + + strictEqual(storageDidClose, true); + + storageChangeListener.dispose(); + storageCloseListener.dispose(); } - test('basics (global)', async function () { - testStorage(storageMainService.globalStorage, true); + test('basics (global)', function () { + return testStorage(storageMainService.globalStorage, true); }); - test('basics (workspace)', async function () { - testStorage(storageMainService.workspaceStorage({ id: generateUuid(), uri: URI.file(isWindows ? 'C:\\testWorkspace' : '/testWorkspace') }), false); + test('basics (workspace)', function () { + return testStorage(storageMainService.workspaceStorage({ id: generateUuid(), uri: URI.file(isWindows ? 'C:\\testWorkspace' : '/testWorkspace') }), false); }); }); diff --git a/src/vs/platform/workspaces/common/workspaces.ts b/src/vs/platform/workspaces/common/workspaces.ts index 66413f2e4e3..491630b4764 100644 --- a/src/vs/platform/workspaces/common/workspaces.ts +++ b/src/vs/platform/workspaces/common/workspaces.ts @@ -161,7 +161,13 @@ export function isWorkspaceIdentifier(obj: unknown): obj is IWorkspaceIdentifier return typeof workspaceIdentifier?.id === 'string' && URI.isUri(workspaceIdentifier.configPath); } -export function reviveIdentifier(identifier: { id: string, uri?: UriComponents, configPath?: UriComponents } | undefined): IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined { +export interface ISerializedWorkspaceIdentifier { + id: string; + uri?: UriComponents; + configPath?: UriComponents; +} + +export function reviveIdentifier(identifier: ISerializedWorkspaceIdentifier | undefined): IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined { if (identifier?.uri) { return { id: identifier.id, uri: URI.revive(identifier.uri) }; } From 5eca02fd99e4970a55363469b3fede1a998d3f64 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 15 Feb 2021 08:18:33 +0100 Subject: [PATCH 129/325] storage - some :lipstick: --- .../sharedProcess/sharedProcessMain.ts | 6 ++--- .../electron-sandbox/workbench/workbench.js | 3 +-- src/vs/platform/storage/common/storageIpc.ts | 4 +-- .../storage/electron-main/storageIpc.ts | 3 --- .../storage/electron-main/storageMain.ts | 25 +++++++------------ .../electron-main/storageMainService.ts | 13 ++++++++-- .../electron-main/storageMainService.test.ts | 8 +++++- 7 files changed, 33 insertions(+), 29 deletions(-) diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 22620bc9345..fe2cb6adcae 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -172,9 +172,9 @@ class SharedProcessMain extends Disposable { await configurationService.initialize(); - // Storage - const storageDatabase = new StorageDatabaseChannelClient(mainProcessService.getChannel('storage'), undefined /* no workspace access for shared process */); - const storageService = new NativeStorageService2(storageDatabase.globalStorage, storageDatabase.workspaceStorage, environmentService); + // Storage (global access only) + const storageDatabaseClient = new StorageDatabaseChannelClient(mainProcessService.getChannel('storage'), undefined); + const storageService = new NativeStorageService2(storageDatabaseClient.globalStorage, undefined, environmentService); services.set(IStorageService, storageService); await storageService.initialize(); diff --git a/src/vs/code/electron-sandbox/workbench/workbench.js b/src/vs/code/electron-sandbox/workbench/workbench.js index 06edaee9432..1946d7f5e3b 100644 --- a/src/vs/code/electron-sandbox/workbench/workbench.js +++ b/src/vs/code/electron-sandbox/workbench/workbench.js @@ -5,7 +5,7 @@ /// -// @ts-check +//@ts-check (function () { 'use strict'; @@ -76,5 +76,4 @@ } //#endregion - }()); diff --git a/src/vs/platform/storage/common/storageIpc.ts b/src/vs/platform/storage/common/storageIpc.ts index cd5550464c6..105f15b1c3a 100644 --- a/src/vs/platform/storage/common/storageIpc.ts +++ b/src/vs/platform/storage/common/storageIpc.ts @@ -14,7 +14,7 @@ export type Value = string; export type Item = [Key, Value]; export interface ISerializableWorkspaceArgument { - workspace: ISerializedWorkspaceIdentifier | undefined + readonly workspace: ISerializedWorkspaceIdentifier | undefined } export interface ISerializableUpdateRequest extends ISerializableWorkspaceArgument { @@ -87,7 +87,7 @@ class GlobalStorageDatabaseClient extends BaseStorageDatabaseClient implements I } } - async close(): Promise { + close(): Promise { // Remove our listeners on `close` because we are no longer // interested in change events from the global database diff --git a/src/vs/platform/storage/electron-main/storageIpc.ts b/src/vs/platform/storage/electron-main/storageIpc.ts index 7eed5eff59e..486a64c06ab 100644 --- a/src/vs/platform/storage/electron-main/storageIpc.ts +++ b/src/vs/platform/storage/electron-main/storageIpc.ts @@ -25,9 +25,6 @@ export class StorageDatabaseChannel extends Disposable implements IServerChannel ) { super(); - // Trigger init of global storage directly from ctor - this.withStorageInitialized(undefined); - this.registerGlobalStorageListeners(); } diff --git a/src/vs/platform/storage/electron-main/storageMain.ts b/src/vs/platform/storage/electron-main/storageMain.ts index 37df63ece3c..3f75df7deb5 100644 --- a/src/vs/platform/storage/electron-main/storageMain.ts +++ b/src/vs/platform/storage/electron-main/storageMain.ts @@ -124,6 +124,14 @@ abstract class BaseStorageMain extends Disposable implements IStorageMain { // one once that is finished and use it from then on this.storage.dispose(); this.storage = storage; + + // Ensure we track wether storage is new or not + const isNewStorage = storage.getBoolean(IS_NEW_KEY); + if (isNewStorage === undefined) { + storage.set(IS_NEW_KEY, true); + } else if (isNewStorage) { + storage.set(IS_NEW_KEY, false); + } })(); } @@ -203,16 +211,9 @@ export class GlobalStorageMain extends BaseStorageMain implements IStorageMain { // Re-emit storage changes via event this._register(storage.onDidChangeStorage(key => this._onDidChangeStorage.fire({ key }))); + // Forward init to SQLite DB await storage.init(); - // Check to see if this is the first time we are "opening" the application - const firstOpen = storage.getBoolean(IS_NEW_KEY); - if (firstOpen === undefined) { - storage.set(IS_NEW_KEY, true); - } else if (firstOpen) { - storage.set(IS_NEW_KEY, false); - } - // Apply global telemetry values as part of the initialization this.updateTelemetryState(storage); @@ -282,14 +283,6 @@ export class WorkspaceStorageMain extends BaseStorageMain implements IStorageMai // result.wasCreated ? StorageHint.STORAGE_DOES_NOT_EXIST : undefined // ); // await workspaceStorage.init(); - - // // Check to see if this is the first time we are "opening" this workspace - // const firstWorkspaceOpen = workspaceStorage.getBoolean(IS_NEW_KEY); - // if (firstWorkspaceOpen === undefined) { - // workspaceStorage.set(IS_NEW_KEY, result.wasCreated); - // } else if (firstWorkspaceOpen) { - // workspaceStorage.set(IS_NEW_KEY, false); - // } // } finally { // mark('code/didInitWorkspaceStorage'); // } diff --git a/src/vs/platform/storage/electron-main/storageMainService.ts b/src/vs/platform/storage/electron-main/storageMainService.ts index 5647a4ea36c..3e4c232099d 100644 --- a/src/vs/platform/storage/electron-main/storageMainService.ts +++ b/src/vs/platform/storage/electron-main/storageMainService.ts @@ -42,8 +42,17 @@ export class StorageMainService implements IStorageMainService { readonly globalStorage = this.createGlobalStorage(); private createGlobalStorage(): IStorageMain { + if (this.globalStorage) { + return this.globalStorage; // only once + } + const globalStorage = new GlobalStorageMain(this.logService, this.environmentService); + // Trigger init of global storage directly from here + // so that we can be ready for access when the window + // needs it (prevents waterfall of initialization) + globalStorage.initialize(); + return globalStorage; } @@ -63,13 +72,13 @@ export class StorageMainService implements IStorageMainService { workspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier): IStorageMain { let workspaceStorage = this.mapWorkspaceToStorage.get(workspace.id); if (!workspaceStorage) { - this.logService.info(`StorageMainService: creating workspace storage (${isWorkspaceIdentifier(workspace) ? workspace.configPath : workspace.uri})`); + this.logService.trace(`StorageMainService: creating workspace storage (${isWorkspaceIdentifier(workspace) ? workspace.configPath : workspace.uri})`); workspaceStorage = this.createWorkspaceStorage(workspace); this.mapWorkspaceToStorage.set(workspace.id, workspaceStorage); once(workspaceStorage.onDidCloseStorage)(() => { - this.logService.info(`StorageMainService: closed workspace storage (${isWorkspaceIdentifier(workspace) ? workspace.configPath : workspace.uri})`); + this.logService.trace(`StorageMainService: closed workspace storage (${isWorkspaceIdentifier(workspace) ? workspace.configPath : workspace.uri})`); this.mapWorkspaceToStorage.delete(workspace.id); }); diff --git a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts index 0383a7264f5..99067897869 100644 --- a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts +++ b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts @@ -13,10 +13,11 @@ import { OPTIONS, parseArgs } from 'vs/platform/environment/node/argv'; import { NativeEnvironmentService } from 'vs/platform/environment/node/environmentService'; import { NullLogService } from 'vs/platform/log/common/log'; import { IStorageMainService, StorageMainService } from 'vs/platform/storage/electron-main/storageMainService'; -import { instanceStorageKey } from 'vs/platform/telemetry/common/telemetry'; +import { currentSessionDateStorageKey, firstSessionDateStorageKey, instanceStorageKey } from 'vs/platform/telemetry/common/telemetry'; import { IStorageChangeEvent, IStorageMain } from 'vs/platform/storage/electron-main/storageMain'; import { generateUuid } from 'vs/base/common/uuid'; import { isWindows } from 'vs/base/common/platform'; +import { IS_NEW_KEY } from 'vs/platform/storage/common/storage'; flakySuite('StorageMainService (native)', function () { @@ -60,6 +61,8 @@ flakySuite('StorageMainService (native)', function () { strictEqual(storage.get(instanceStorageKey), undefined); await storage.initialize(); strictEqual(typeof storage.get(instanceStorageKey), 'string'); + strictEqual(typeof storage.get(firstSessionDateStorageKey), 'string'); + strictEqual(typeof storage.get(currentSessionDateStorageKey), 'string'); } let storageChangeEvent: IStorageChangeEvent | undefined = undefined; @@ -89,6 +92,9 @@ flakySuite('StorageMainService (native)', function () { strictEqual(storage.items.size, size + 2); + // IS_NEW + strictEqual(storage.get(IS_NEW_KEY), true); + // Close await storage.close(); From 02613ef2b41e5802df83cf248d47428a37352a47 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 15 Feb 2021 11:14:14 +0100 Subject: [PATCH 130/325] storage - implement workspace storage and fix tests --- src/vs/platform/storage/common/storageIpc.ts | 18 +- .../storage/electron-main/storageIpc.ts | 8 +- .../storage/electron-main/storageMain.ts | 202 ++++++++---------- .../electron-main/storageMainService.ts | 14 +- .../electron-sandbox/storageService2.ts | 14 +- .../electron-main/storageMainService.test.ts | 52 ++++- .../platform/workspaces/common/workspaces.ts | 41 ++-- .../workspaces/test/common/workspaces.test.ts | 17 +- .../performance/browser/perfviewEditor.ts | 1 + .../electron-browser/desktop.main.ts | 7 +- .../electron-sandbox/desktop.main.ts | 7 +- .../browser/configurationService.ts | 6 +- .../services/timer/browser/timerService.ts | 10 + 13 files changed, 233 insertions(+), 164 deletions(-) diff --git a/src/vs/platform/storage/common/storageIpc.ts b/src/vs/platform/storage/common/storageIpc.ts index 105f15b1c3a..5669ec1f22f 100644 --- a/src/vs/platform/storage/common/storageIpc.ts +++ b/src/vs/platform/storage/common/storageIpc.ts @@ -7,17 +7,17 @@ import { Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { IStorageDatabase, IStorageItemsChangeEvent, IUpdateRequest } from 'vs/base/parts/storage/common/storage'; -import { ISerializedWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IEmptyWorkspaceIdentifier, ISerializedSingleFolderWorkspaceIdentifier, ISerializedWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; export type Key = string; export type Value = string; export type Item = [Key, Value]; -export interface ISerializableWorkspaceArgument { - readonly workspace: ISerializedWorkspaceIdentifier | undefined +export interface IBaseSerializableStorageRequest { + readonly workspace: ISerializedWorkspaceIdentifier | ISerializedSingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined } -export interface ISerializableUpdateRequest extends ISerializableWorkspaceArgument { +export interface ISerializableUpdateRequest extends IBaseSerializableStorageRequest { insert?: Item[]; delete?: Key[]; } @@ -31,12 +31,12 @@ abstract class BaseStorageDatabaseClient extends Disposable implements IStorageD abstract onDidChangeItemsExternal: Event; - constructor(protected channel: IChannel, private workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined) { + constructor(protected channel: IChannel, private workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined) { super(); } async getItems(): Promise> { - const serializableRequest: ISerializableWorkspaceArgument = { workspace: this.workspace }; + const serializableRequest: IBaseSerializableStorageRequest = { workspace: this.workspace }; const items: Item[] = await this.channel.call('getItems', serializableRequest); return new Map(items); @@ -57,7 +57,7 @@ abstract class BaseStorageDatabaseClient extends Disposable implements IStorageD } async close(): Promise { - const serializableRequest: ISerializableWorkspaceArgument = { workspace: this.workspace }; + const serializableRequest: IBaseSerializableStorageRequest = { workspace: this.workspace }; return this.channel.call('close', serializableRequest); } @@ -101,7 +101,7 @@ class WorkspaceStorageDatabaseClient extends BaseStorageDatabaseClient implement readonly onDidChangeItemsExternal = Event.None; // unsupported for workspace storage because we only ever write from one window - constructor(channel: IChannel, workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier) { + constructor(channel: IChannel, workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier) { super(channel, workspace); } } @@ -113,7 +113,7 @@ export class StorageDatabaseChannelClient extends Disposable { constructor( private channel: IChannel, - private workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined + private workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined ) { super(); } diff --git a/src/vs/platform/storage/electron-main/storageIpc.ts b/src/vs/platform/storage/electron-main/storageIpc.ts index 486a64c06ab..27084af2ee6 100644 --- a/src/vs/platform/storage/electron-main/storageIpc.ts +++ b/src/vs/platform/storage/electron-main/storageIpc.ts @@ -7,10 +7,10 @@ import { Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { IServerChannel } from 'vs/base/parts/ipc/common/ipc'; import { ILogService } from 'vs/platform/log/common/log'; -import { ISerializableItemsChangeEvent, ISerializableUpdateRequest, ISerializableWorkspaceArgument, Key, Value } from 'vs/platform/storage/common/storageIpc'; +import { ISerializableItemsChangeEvent, ISerializableUpdateRequest, IBaseSerializableStorageRequest, Key, Value } from 'vs/platform/storage/common/storageIpc'; import { IStorageChangeEvent, IStorageMain } from 'vs/platform/storage/electron-main/storageMain'; import { IStorageMainService } from 'vs/platform/storage/electron-main/storageMainService'; -import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier, reviveIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IEmptyWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier, reviveIdentifier } from 'vs/platform/workspaces/common/workspaces'; export class StorageDatabaseChannel extends Disposable implements IServerChannel { @@ -77,7 +77,7 @@ export class StorageDatabaseChannel extends Disposable implements IServerChannel //#endregion - async call(_: unknown, command: string, arg: ISerializableWorkspaceArgument): Promise { + async call(_: unknown, command: string, arg: IBaseSerializableStorageRequest): Promise { const workspace = reviveIdentifier(arg.workspace); // Get storage to be ready @@ -119,7 +119,7 @@ export class StorageDatabaseChannel extends Disposable implements IServerChannel } } - private async withStorageInitialized(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined): Promise { + private async withStorageInitialized(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined): Promise { const storage = workspace ? this.storageMainService.workspaceStorage(workspace) : this.storageMainService.globalStorage; try { diff --git a/src/vs/platform/storage/electron-main/storageMain.ts b/src/vs/platform/storage/electron-main/storageMain.ts index 3f75df7deb5..18494b1b00b 100644 --- a/src/vs/platform/storage/electron-main/storageMain.ts +++ b/src/vs/platform/storage/electron-main/storageMain.ts @@ -3,17 +3,19 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { promises } from 'fs'; +import { exists, writeFile } from 'vs/base/node/pfs'; import { Event, Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { ILogService, LogLevel } from 'vs/platform/log/common/log'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { SQLiteStorageDatabase, ISQLiteStorageDatabaseLoggingOptions } from 'vs/base/parts/storage/node/storage'; -import { Storage, InMemoryStorageDatabase } from 'vs/base/parts/storage/common/storage'; +import { Storage, InMemoryStorageDatabase, StorageHint, IStorage } from 'vs/base/parts/storage/common/storage'; import { join } from 'vs/base/common/path'; import { IS_NEW_KEY } from 'vs/platform/storage/common/storage'; import { currentSessionDateStorageKey, firstSessionDateStorageKey, instanceStorageKey, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry'; import { generateUuid } from 'vs/base/common/uuid'; -import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IEmptyWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; /** * Provides access to global and workspace storage from the @@ -107,30 +109,34 @@ abstract class BaseStorageMain extends Disposable implements IStorageMain { private readonly _onDidCloseStorage = this._register(new Emitter()); readonly onDidCloseStorage = this._onDidCloseStorage.event; - private storage = new Storage(new InMemoryStorageDatabase()); // storage is in-memory until initialized + private storage: IStorage = new Storage(new InMemoryStorageDatabase()); // storage is in-memory until initialized private initializePromise: Promise | undefined = undefined; - constructor() { + constructor(protected readonly logService: ILogService) { super(); } initialize(): Promise { if (!this.initializePromise) { this.initializePromise = (async () => { - const storage = await this.doInitialize(); + try { + const storage = await this.doInitialize(); - // Replace our in-memory storage with the initialized - // one once that is finished and use it from then on - this.storage.dispose(); - this.storage = storage; + // Replace our in-memory storage with the initialized + // one once that is finished and use it from then on + this.storage.dispose(); + this.storage = storage; - // Ensure we track wether storage is new or not - const isNewStorage = storage.getBoolean(IS_NEW_KEY); - if (isNewStorage === undefined) { - storage.set(IS_NEW_KEY, true); - } else if (isNewStorage) { - storage.set(IS_NEW_KEY, false); + // Ensure we track wether storage is new or not + const isNewStorage = storage.getBoolean(IS_NEW_KEY); + if (isNewStorage === undefined) { + storage.set(IS_NEW_KEY, true); + } else if (isNewStorage) { + storage.set(IS_NEW_KEY, false); + } + } catch (error) { + this.logService.error(`StorageMain#initialize(): Unable to init storage due to ${error}`); } })(); } @@ -138,7 +144,14 @@ abstract class BaseStorageMain extends Disposable implements IStorageMain { return this.initializePromise; } - protected abstract doInitialize(): Promise; + protected createLogginOptions(): ISQLiteStorageDatabaseLoggingOptions { + return { + logTrace: (this.logService.getLevel() === LogLevel.Trace) ? msg => this.logService.trace(msg) : undefined, + logError: error => this.logService.error(error) + }; + } + + protected abstract doInitialize(): Promise; get items(): Map { return this.storage.items; } @@ -183,20 +196,13 @@ export class GlobalStorageMain extends BaseStorageMain implements IStorageMain { private static readonly STORAGE_NAME = 'state.vscdb'; constructor( - @ILogService private readonly logService: ILogService, - @IEnvironmentService private readonly environmentService: IEnvironmentService + logService: ILogService, + private readonly environmentService: IEnvironmentService ) { - super(); + super(logService); } - private createLogginOptions(): ISQLiteStorageDatabaseLoggingOptions { - return { - logTrace: (this.logService.getLevel() === LogLevel.Trace) ? msg => this.logService.trace(msg) : undefined, - logError: error => this.logService.error(error) - }; - } - - protected async doInitialize(): Promise { + protected async doInitialize(): Promise { let storagePath: string; if (!!this.environmentService.extensionTestsLocationURI) { storagePath = SQLiteStorageDatabase.IN_MEMORY_PATH; // no storage during extension tests! @@ -204,6 +210,7 @@ export class GlobalStorageMain extends BaseStorageMain implements IStorageMain { storagePath = join(this.environmentService.globalStorageHome.fsPath, GlobalStorageMain.STORAGE_NAME); } + // Create Storage const storage = new Storage(new SQLiteStorageDatabase(storagePath, { logging: this.createLogginOptions() })); @@ -255,103 +262,80 @@ export class GlobalStorageMain extends BaseStorageMain implements IStorageMain { export class WorkspaceStorageMain extends BaseStorageMain implements IStorageMain { - constructor(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier) { - super(); + private static readonly WORKSPACE_STORAGE_NAME = 'state.vscdb'; + private static readonly WORKSPACE_META_NAME = 'workspace.json'; + + constructor( + private workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier, + logService: ILogService, + private readonly environmentService: IEnvironmentService + ) { + super(logService); } - protected async doInitialize(): Promise { - const storage = new Storage(new InMemoryStorageDatabase()); + protected async doInitialize(): Promise { + + // Prepare workspace storage folder for DB + const { storageFilePath, wasCreated } = await this.prepareWorkspaceStorageFolder(); + + // Create Storage + const storage = new Storage(new SQLiteStorageDatabase(storageFilePath, { + logging: this.createLogginOptions() + }), { hint: wasCreated ? StorageHint.STORAGE_DOES_NOT_EXIST : undefined }); // Re-emit storage changes via event this._register(storage.onDidChangeStorage(key => this._onDidChangeStorage.fire({ key }))); + // Forward init to SQLite DB + await storage.init(); + return storage; + } - // private async initializeWorkspaceStorage(payload: IWorkspaceInitializationPayload): Promise { + private async prepareWorkspaceStorageFolder(): Promise<{ storageFilePath: string, wasCreated: boolean }> { - // // Prepare workspace storage folder for DB - // try { - // const result = await this.prepareWorkspaceStorageFolder(payload); + // Return early with in-memory when running extension tests + if (!!this.environmentService.extensionTestsLocationURI) { + return { storageFilePath: SQLiteStorageDatabase.IN_MEMORY_PATH, wasCreated: true }; + } - // const useInMemoryStorage = !!this.environmentService.extensionTestsLocationURI; // no storage during extension tests! + // Otherwise, ensure the storage folder exists on disk + const workspaceStorageFolderPath = join(this.environmentService.workspaceStorageHome.fsPath, this.workspace.id); + const workspaceStorageDatabasePath = join(workspaceStorageFolderPath, WorkspaceStorageMain.WORKSPACE_STORAGE_NAME); - // // Create workspace storage and initialize - // mark('code/willInitWorkspaceStorage'); - // try { - // const workspaceStorage = this.createWorkspaceStorage( - // useInMemoryStorage ? SQLiteStorageDatabase.IN_MEMORY_PATH : join(result.path, NativeStorageService.WORKSPACE_STORAGE_NAME), - // result.wasCreated ? StorageHint.STORAGE_DOES_NOT_EXIST : undefined - // ); - // await workspaceStorage.init(); - // } finally { - // mark('code/didInitWorkspaceStorage'); - // } - // } catch (error) { - // this.logService.error(`[storage] initializeWorkspaceStorage(): Unable to init workspace storage due to ${error}`); - // } - // } + const storageExists = await exists(workspaceStorageFolderPath); + if (storageExists) { + return { storageFilePath: workspaceStorageDatabasePath, wasCreated: false }; + } - // private createWorkspaceStorage(workspaceStoragePath: string, hint?: StorageHint): IStorage { + await promises.mkdir(workspaceStorageFolderPath, { recursive: true }); - // // Logger for workspace storage - // const workspaceLoggingOptions: ISQLiteStorageDatabaseLoggingOptions = { - // logTrace: (this.logService.getLevel() === LogLevel.Trace) ? msg => this.logService.trace(msg) : undefined, - // logError: error => this.logService.error(error) - // }; + // Write metadata into folder + this.ensureWorkspaceStorageFolderMeta(workspaceStorageFolderPath); - // // Dispose old (if any) - // dispose(this.workspaceStorage); - // dispose(this.workspaceStorageListener); + return { storageFilePath: workspaceStorageDatabasePath, wasCreated: true }; + } - // // Create new - // this.workspaceStoragePath = workspaceStoragePath; - // this.workspaceStorage = new Storage(new SQLiteStorageDatabase(workspaceStoragePath, { logging: workspaceLoggingOptions }), { hint }); - // this.workspaceStorageListener = this.workspaceStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.WORKSPACE, key)); + private ensureWorkspaceStorageFolderMeta(workspaceStorageFolderPath: string): void { + let meta: object | undefined = undefined; + if (isSingleFolderWorkspaceIdentifier(this.workspace)) { + meta = { folder: this.workspace.uri.toString() }; + } else if (isWorkspaceIdentifier(this.workspace)) { + meta = { workspace: this.workspace.configPath.toString() }; + } - // return this.workspaceStorage; - // } - - // private getWorkspaceStorageFolderPath(payload: IWorkspaceInitializationPayload): string { - // return join(this.environmentService.workspaceStorageHome.fsPath, payload.id); // workspace home + workspace id; - // } - - // private async prepareWorkspaceStorageFolder(payload: IWorkspaceInitializationPayload): Promise<{ path: string, wasCreated: boolean }> { - // const workspaceStorageFolderPath = this.getWorkspaceStorageFolderPath(payload); - - // const storageExists = await exists(workspaceStorageFolderPath); - // if (storageExists) { - // return { path: workspaceStorageFolderPath, wasCreated: false }; - // } - - // await promises.mkdir(workspaceStorageFolderPath, { recursive: true }); - - // // Write metadata into folder - // this.ensureWorkspaceStorageFolderMeta(payload); - - // return { path: workspaceStorageFolderPath, wasCreated: true }; - // } - - // private ensureWorkspaceStorageFolderMeta(payload: IWorkspaceInitializationPayload): void { - // let meta: object | undefined = undefined; - // if (isSingleFolderWorkspaceIdentifier(payload)) { - // meta = { folder: payload.uri.toString() }; - // } else if (isWorkspaceIdentifier(payload)) { - // meta = { workspace: payload.configPath.toString() }; - // } - - // if (meta) { - // (async () => { - // try { - // const workspaceStorageMetaPath = join(this.getWorkspaceStorageFolderPath(payload), NativeStorageService.WORKSPACE_META_NAME); - // const storageExists = await exists(workspaceStorageMetaPath); - // if (!storageExists) { - // await writeFile(workspaceStorageMetaPath, JSON.stringify(meta, undefined, 2)); - // } - // } catch (error) { - // this.logService.error(error); - // } - // })(); - // } - // } + if (meta) { + (async () => { + try { + const workspaceStorageMetaPath = join(workspaceStorageFolderPath, WorkspaceStorageMain.WORKSPACE_META_NAME); + const storageExists = await exists(workspaceStorageMetaPath); + if (!storageExists) { + await writeFile(workspaceStorageMetaPath, JSON.stringify(meta, undefined, 2)); + } + } catch (error) { + this.logService.error(`StorageMain#ensureWorkspaceStorageFolderMeta(): Unable to create workspace storage metadata due to ${error}`); + } + })(); + } } } diff --git a/src/vs/platform/storage/electron-main/storageMainService.ts b/src/vs/platform/storage/electron-main/storageMainService.ts index 3e4c232099d..38e8d235a33 100644 --- a/src/vs/platform/storage/electron-main/storageMainService.ts +++ b/src/vs/platform/storage/electron-main/storageMainService.ts @@ -8,7 +8,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; import { GlobalStorageMain, IStorageMain, WorkspaceStorageMain } from 'vs/platform/storage/electron-main/storageMain'; -import { ISingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IEmptyWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; export const IStorageMainService = createDecorator('storageMainService'); @@ -24,7 +24,7 @@ export interface IStorageMainService { /** * Provides access to the workspace storage specific to a single window. */ - workspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier): IStorageMain; + workspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier): IStorageMain; } export class StorageMainService implements IStorageMainService { @@ -63,22 +63,22 @@ export class StorageMainService implements IStorageMainService { private readonly mapWorkspaceToStorage = new Map(); - private createWorkspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier): IStorageMain { - const workspaceStorage = new WorkspaceStorageMain(workspace); + private createWorkspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier): IStorageMain { + const workspaceStorage = new WorkspaceStorageMain(workspace, this.logService, this.environmentService); return workspaceStorage; } - workspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier): IStorageMain { + workspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier): IStorageMain { let workspaceStorage = this.mapWorkspaceToStorage.get(workspace.id); if (!workspaceStorage) { - this.logService.trace(`StorageMainService: creating workspace storage (${isWorkspaceIdentifier(workspace) ? workspace.configPath : workspace.uri})`); + this.logService.trace(`StorageMainService: creating workspace storage (${workspace.id})`); workspaceStorage = this.createWorkspaceStorage(workspace); this.mapWorkspaceToStorage.set(workspace.id, workspaceStorage); once(workspaceStorage.onDidCloseStorage)(() => { - this.logService.trace(`StorageMainService: closed workspace storage (${isWorkspaceIdentifier(workspace) ? workspace.configPath : workspace.uri})`); + this.logService.trace(`StorageMainService: closed workspace storage (${workspace.id})`); this.mapWorkspaceToStorage.delete(workspace.id); }); diff --git a/src/vs/platform/storage/electron-sandbox/storageService2.ts b/src/vs/platform/storage/electron-sandbox/storageService2.ts index e5748a183f0..97fc6da4e21 100644 --- a/src/vs/platform/storage/electron-sandbox/storageService2.ts +++ b/src/vs/platform/storage/electron-sandbox/storageService2.ts @@ -10,6 +10,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces'; import { assertIsDefined } from 'vs/base/common/types'; import { Promises, RunOnceScheduler, runWhenIdle } from 'vs/base/common/async'; +import { mark } from 'vs/base/common/performance'; export class NativeStorageService2 extends AbstractStorageService { @@ -47,10 +48,15 @@ export class NativeStorageService2 extends AbstractStorageService { private async doInitialize(): Promise { // Init all storage locations - await Promises.settled([ - this.globalStorage.init(), - this.workspaceStorage?.init() ?? Promise.resolve() - ]); + mark('code/willInitStorage'); + try { + await Promises.settled([ + this.globalStorage.init(), + this.workspaceStorage?.init() ?? Promise.resolve() + ]); + } finally { + mark('code/didInitStorage'); + } // On some OS we do not get enough time to persist state on shutdown (e.g. when // Windows restarts after applying updates). In other cases, VSCode might crash, diff --git a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts index 99067897869..025bbf6226c 100644 --- a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts +++ b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts @@ -12,18 +12,19 @@ import { flakySuite, getRandomTestPath } from 'vs/base/test/node/testUtils'; import { OPTIONS, parseArgs } from 'vs/platform/environment/node/argv'; import { NativeEnvironmentService } from 'vs/platform/environment/node/environmentService'; import { NullLogService } from 'vs/platform/log/common/log'; -import { IStorageMainService, StorageMainService } from 'vs/platform/storage/electron-main/storageMainService'; +import { StorageMainService } from 'vs/platform/storage/electron-main/storageMainService'; import { currentSessionDateStorageKey, firstSessionDateStorageKey, instanceStorageKey } from 'vs/platform/telemetry/common/telemetry'; import { IStorageChangeEvent, IStorageMain } from 'vs/platform/storage/electron-main/storageMain'; import { generateUuid } from 'vs/base/common/uuid'; import { isWindows } from 'vs/base/common/platform'; import { IS_NEW_KEY } from 'vs/platform/storage/common/storage'; +import { joinPath } from 'vs/base/common/resources'; flakySuite('StorageMainService (native)', function () { class StorageTestEnvironmentService extends NativeEnvironmentService { - constructor(private globalStorageFolderPath: URI, private _extensionsPath: string) { + constructor(private globalStorageFolderPath: URI, private workspaceStorageFolderPath: URI, private _extensionsPath: string) { super(parseArgs(process.argv, OPTIONS)); } @@ -31,29 +32,37 @@ flakySuite('StorageMainService (native)', function () { return this.globalStorageFolderPath; } + get workspaceStorageHome(): URI { + return this.workspaceStorageFolderPath; + } + get extensionsPath(): string { return this._extensionsPath; } } let testDir: string; - let storageMainService: IStorageMainService; + let environmentService: StorageTestEnvironmentService; setup(async () => { testDir = getRandomTestPath(tmpdir(), 'vsctests', 'storageMainService'); await promises.mkdir(testDir, { recursive: true }); - storageMainService = new StorageMainService(new NullLogService(), new StorageTestEnvironmentService(URI.file(testDir), testDir)); + const globalStorageFolder = joinPath(URI.file(testDir), 'globalStorage'); + const workspaceStorageFolder = joinPath(URI.file(testDir), 'workspaceStorage'); + + await promises.mkdir(globalStorageFolder.fsPath, { recursive: true }); + + environmentService = new StorageTestEnvironmentService(globalStorageFolder, workspaceStorageFolder, testDir); }); - teardown(async () => { - await storageMainService.globalStorage.close(); - + teardown(() => { return rimraf(testDir); }); - async function testStorage(storage: IStorageMain, isGlobal: boolean): Promise { + async function testStorage(storageFn: () => IStorageMain, isGlobal: boolean): Promise { + let storage = storageFn(); // Telemetry: added after init if (isGlobal) { @@ -63,6 +72,8 @@ flakySuite('StorageMainService (native)', function () { strictEqual(typeof storage.get(instanceStorageKey), 'string'); strictEqual(typeof storage.get(firstSessionDateStorageKey), 'string'); strictEqual(typeof storage.get(currentSessionDateStorageKey), 'string'); + } else { + await storage.initialize(); } let storageChangeEvent: IStorageChangeEvent | undefined = undefined; @@ -93,7 +104,7 @@ flakySuite('StorageMainService (native)', function () { strictEqual(storage.items.size, size + 2); // IS_NEW - strictEqual(storage.get(IS_NEW_KEY), true); + strictEqual(storage.getBoolean(IS_NEW_KEY), true); // Close await storage.close(); @@ -102,13 +113,32 @@ flakySuite('StorageMainService (native)', function () { storageChangeListener.dispose(); storageCloseListener.dispose(); + + // Reopen + storage = storageFn(); + await storage.initialize(); + + strictEqual(storage.getNumber('barNumber'), 55); + strictEqual(storage.getBoolean('barBoolean'), true); + + await storage.close(); } test('basics (global)', function () { - return testStorage(storageMainService.globalStorage, true); + return testStorage(() => { + const storageMainService = new StorageMainService(new NullLogService(), environmentService); + + return storageMainService.globalStorage; + }, true); }); test('basics (workspace)', function () { - return testStorage(storageMainService.workspaceStorage({ id: generateUuid(), uri: URI.file(isWindows ? 'C:\\testWorkspace' : '/testWorkspace') }), false); + const workspace = { id: generateUuid(), uri: URI.file(isWindows ? 'C:\\testWorkspace' : '/testWorkspace') }; + + return testStorage(() => { + const storageMainService = new StorageMainService(new NullLogService(), environmentService); + + return storageMainService.workspaceStorage(workspace); + }, false); }); }); diff --git a/src/vs/platform/workspaces/common/workspaces.ts b/src/vs/platform/workspaces/common/workspaces.ts index 491630b4764..897a204578e 100644 --- a/src/vs/platform/workspaces/common/workspaces.ts +++ b/src/vs/platform/workspaces/common/workspaces.ts @@ -116,6 +116,10 @@ export interface ISingleFolderWorkspaceIdentifier extends IBaseWorkspaceIdentifi uri: URI; } +export interface ISerializedSingleFolderWorkspaceIdentifier extends IBaseWorkspaceIdentifier { + uri: UriComponents; +} + export function isSingleFolderWorkspaceIdentifier(obj: unknown): obj is ISingleFolderWorkspaceIdentifier { const singleFolderIdentifier = obj as ISingleFolderWorkspaceIdentifier | undefined; @@ -133,6 +137,10 @@ export interface IWorkspaceIdentifier extends IBaseWorkspaceIdentifier { configPath: URI; } +export interface ISerializedWorkspaceIdentifier extends IBaseWorkspaceIdentifier { + configPath: UriComponents; +} + export function toWorkspaceIdentifier(workspace: IWorkspace): IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined { // Multi root @@ -161,19 +169,28 @@ export function isWorkspaceIdentifier(obj: unknown): obj is IWorkspaceIdentifier return typeof workspaceIdentifier?.id === 'string' && URI.isUri(workspaceIdentifier.configPath); } -export interface ISerializedWorkspaceIdentifier { - id: string; - uri?: UriComponents; - configPath?: UriComponents; -} +export function reviveIdentifier(identifier: undefined): undefined; +export function reviveIdentifier(identifier: ISerializedWorkspaceIdentifier): IWorkspaceIdentifier; +export function reviveIdentifier(identifier: ISerializedSingleFolderWorkspaceIdentifier): ISingleFolderWorkspaceIdentifier; +export function reviveIdentifier(identifier: IEmptyWorkspaceIdentifier): IEmptyWorkspaceIdentifier; +export function reviveIdentifier(identifier: ISerializedWorkspaceIdentifier | ISerializedSingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined): IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined; +export function reviveIdentifier(identifier: ISerializedWorkspaceIdentifier | ISerializedSingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined): IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined { -export function reviveIdentifier(identifier: ISerializedWorkspaceIdentifier | undefined): IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined { - if (identifier?.uri) { - return { id: identifier.id, uri: URI.revive(identifier.uri) }; + // Single Folder + const singleFolderIdentifierCandidate = identifier as ISerializedSingleFolderWorkspaceIdentifier | undefined; + if (singleFolderIdentifierCandidate?.uri) { + return { id: singleFolderIdentifierCandidate.id, uri: URI.revive(singleFolderIdentifierCandidate.uri) }; } - if (identifier?.configPath) { - return { id: identifier.id, configPath: URI.revive(identifier.configPath) }; + // Multi folder + const workspaceIdentifierCandidate = identifier as ISerializedWorkspaceIdentifier | undefined; + if (workspaceIdentifierCandidate?.configPath) { + return { id: workspaceIdentifierCandidate.id, configPath: URI.revive(workspaceIdentifierCandidate.configPath) }; + } + + // Empty + if (identifier?.id) { + return { id: identifier.id }; } return undefined; @@ -183,9 +200,9 @@ export function isUntitledWorkspace(path: URI, environmentService: IEnvironmentS return extUriBiasedIgnorePathCase.isEqualOrParent(path, environmentService.untitledWorkspacesHome); } -export interface IEmptyWorkspaceInitializationPayload extends IBaseWorkspaceIdentifier { } +export interface IEmptyWorkspaceIdentifier extends IBaseWorkspaceIdentifier { } -export type IWorkspaceInitializationPayload = IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceInitializationPayload; +export type IWorkspaceInitializationPayload = IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier; //#endregion diff --git a/src/vs/platform/workspaces/test/common/workspaces.test.ts b/src/vs/platform/workspaces/test/common/workspaces.test.ts index 270eaee4899..cb8c60e8668 100644 --- a/src/vs/platform/workspaces/test/common/workspaces.test.ts +++ b/src/vs/platform/workspaces/test/common/workspaces.test.ts @@ -5,10 +5,25 @@ import * as assert from 'assert'; import { URI } from 'vs/base/common/uri'; -import { hasWorkspaceFileExtension, toWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { hasWorkspaceFileExtension, toWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, ISerializedWorkspaceIdentifier, reviveIdentifier, ISerializedSingleFolderWorkspaceIdentifier, IEmptyWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; suite('Workspaces', () => { + test('reviveIdentifier', () => { + let serializedWorkspaceIdentifier: ISerializedWorkspaceIdentifier = { id: 'id', configPath: URI.file('foo').toJSON() }; + assert.strictEqual(isWorkspaceIdentifier(reviveIdentifier(serializedWorkspaceIdentifier)), true); + + let serializedSingleFolderWorkspaceIdentifier: ISerializedSingleFolderWorkspaceIdentifier = { id: 'id', uri: URI.file('foo').toJSON() }; + assert.strictEqual(isSingleFolderWorkspaceIdentifier(reviveIdentifier(serializedSingleFolderWorkspaceIdentifier)), true); + + let serializedEmptyWorkspaceIdentifier: IEmptyWorkspaceIdentifier = { id: 'id' }; + assert.strictEqual(reviveIdentifier(serializedEmptyWorkspaceIdentifier).id, serializedEmptyWorkspaceIdentifier.id); + assert.strictEqual(isWorkspaceIdentifier(serializedEmptyWorkspaceIdentifier), false); + assert.strictEqual(isSingleFolderWorkspaceIdentifier(serializedEmptyWorkspaceIdentifier), false); + + assert.strictEqual(reviveIdentifier(undefined), undefined); + }); + test('hasWorkspaceFileExtension', () => { assert.strictEqual(hasWorkspaceFileExtension('something'), false); assert.strictEqual(hasWorkspaceFileExtension('something.code-workspace'), true); diff --git a/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts b/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts index 93974d117c3..51d3d495873 100644 --- a/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts +++ b/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts @@ -174,6 +174,7 @@ class PerfModelContentProvider implements ITextModelContentProvider { table.push(['window.loadUrl() => begin to require(workbench.desktop.main.js)', metrics.timers.ellapsedWindowLoadToRequire, '[main->renderer]', StartupKindToString(metrics.windowKind)]); table.push(['require(workbench.desktop.main.js)', metrics.timers.ellapsedRequire, '[renderer]', `cached data: ${(metrics.didUseCachedData ? 'YES' : 'NO')}${stats ? `, node_modules took ${stats.nodeRequireTotal}ms` : ''}`]); table.push(['wait for shell environment', metrics.timers.ellapsedWaitForShellEnv, '[renderer]', undefined]); + table.push(['init storage (global & workspace)', metrics.timers.ellapsedStorageInit, '[renderer]', undefined]); table.push(['require & init workspace storage', metrics.timers.ellapsedWorkspaceStorageInit, '[renderer]', undefined]); table.push(['init workspace service', metrics.timers.ellapsedWorkspaceServiceInit, '[renderer]', undefined]); if (isWeb) { diff --git a/src/vs/workbench/electron-browser/desktop.main.ts b/src/vs/workbench/electron-browser/desktop.main.ts index 8b6823290e0..411501667ec 100644 --- a/src/vs/workbench/electron-browser/desktop.main.ts +++ b/src/vs/workbench/electron-browser/desktop.main.ts @@ -84,7 +84,10 @@ class DesktopMain extends Disposable { private reviveUris() { // Workspace - this.configuration.workspace = reviveIdentifier(this.configuration.workspace); + const workspace = reviveIdentifier(this.configuration.workspace); + if (isWorkspaceIdentifier(workspace) || isSingleFolderWorkspaceIdentifier(workspace)) { + this.configuration.workspace = workspace; + } // Files const filesToWait = this.configuration.filesToWait; @@ -321,7 +324,7 @@ class DesktopMain extends Disposable { } private async createStorageService(payload: IWorkspaceInitializationPayload, logService: ILogService, mainProcessService: IMainProcessService): Promise { - const storageDataBaseClient = new StorageDatabaseChannelClient(mainProcessService.getChannel('storage'), isWorkspaceIdentifier(payload) || isSingleFolderWorkspaceIdentifier(payload) ? payload : undefined); + const storageDataBaseClient = new StorageDatabaseChannelClient(mainProcessService.getChannel('storage'), payload); let storageService: NativeStorageService | NativeStorageService2; if (this.configuration.enableExperimentalMainProcessWorkspaceStorage) { diff --git a/src/vs/workbench/electron-sandbox/desktop.main.ts b/src/vs/workbench/electron-sandbox/desktop.main.ts index a28d6151bf8..6edfbc6d1d4 100644 --- a/src/vs/workbench/electron-sandbox/desktop.main.ts +++ b/src/vs/workbench/electron-sandbox/desktop.main.ts @@ -73,7 +73,10 @@ class DesktopMain extends Disposable { private reviveUris() { // Workspace - this.configuration.workspace = reviveIdentifier(this.configuration.workspace); + const workspace = reviveIdentifier(this.configuration.workspace); + if (isWorkspaceIdentifier(workspace) || isSingleFolderWorkspaceIdentifier(workspace)) { + this.configuration.workspace = workspace; + } // Files const filesToWait = this.configuration.filesToWait; @@ -294,7 +297,7 @@ class DesktopMain extends Disposable { } private async createStorageService(payload: IWorkspaceInitializationPayload, mainProcessService: IMainProcessService): Promise { - const storageDataBaseClient = new StorageDatabaseChannelClient(mainProcessService.getChannel('storage'), isWorkspaceIdentifier(payload) || isSingleFolderWorkspaceIdentifier(payload) ? payload : undefined); + const storageDataBaseClient = new StorageDatabaseChannelClient(mainProcessService.getChannel('storage'), payload); const storageService = new NativeStorageService2(storageDataBaseClient.globalStorage, storageDataBaseClient.workspaceStorage, this.environmentService); try { diff --git a/src/vs/workbench/services/configuration/browser/configurationService.ts b/src/vs/workbench/services/configuration/browser/configurationService.ts index 5577ffbb2b0..fa4552e36f9 100644 --- a/src/vs/workbench/services/configuration/browser/configurationService.ts +++ b/src/vs/workbench/services/configuration/browser/configurationService.ts @@ -17,7 +17,7 @@ import { Configuration } from 'vs/workbench/services/configuration/common/config import { FOLDER_CONFIG_FOLDER_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId, IConfigurationCache, machineSettingsSchemaId, LOCAL_MACHINE_SCOPES, IWorkbenchConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions, allSettings, windowSettings, resourceSettings, applicationSettings, machineSettings, machineOverridableSettings, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; -import { IWorkspaceIdentifier, isWorkspaceIdentifier, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, IWorkspaceInitializationPayload, IEmptyWorkspaceInitializationPayload, useSlashForPath, getStoredWorkspaceFolder, isSingleFolderWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, toWorkspaceFolders } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceIdentifier, isWorkspaceIdentifier, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, IWorkspaceInitializationPayload, IEmptyWorkspaceIdentifier, useSlashForPath, getStoredWorkspaceFolder, isSingleFolderWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, toWorkspaceFolders } from 'vs/platform/workspaces/common/workspaces'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ConfigurationEditingService, EditableConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditingService'; import { WorkspaceConfiguration, FolderConfiguration, RemoteUserConfiguration, UserConfiguration } from 'vs/workbench/services/configuration/browser/configuration'; @@ -418,8 +418,8 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat return Promise.resolve(workspace); } - private createEmptyWorkspace(emptyWorkspacePayload: IEmptyWorkspaceInitializationPayload): Promise { - const workspace = new Workspace(emptyWorkspacePayload.id, [], null, uri => this.uriIdentityService.extUri.ignorePathCasing(uri)); + private createEmptyWorkspace(emptyWorkspaceIdentifier: IEmptyWorkspaceIdentifier): Promise { + const workspace = new Workspace(emptyWorkspaceIdentifier.id, [], null, uri => this.uriIdentityService.extUri.ignorePathCasing(uri)); workspace.initialized = true; return Promise.resolve(workspace); } diff --git a/src/vs/workbench/services/timer/browser/timerService.ts b/src/vs/workbench/services/timer/browser/timerService.ts index f4bc25a6066..324de644b65 100644 --- a/src/vs/workbench/services/timer/browser/timerService.ts +++ b/src/vs/workbench/services/timer/browser/timerService.ts @@ -46,6 +46,7 @@ export interface IMemoryInfo { "timers.ellapsedExtensions" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "timers.ellapsedExtensionsReady" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "timers.ellapsedRequire" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, + "timers.ellapsedStorageInit" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "timers.ellapsedWorkspaceStorageInit" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "timers.ellapsedWorkspaceServiceInit" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "timers.ellapsedRequiredUserDataInit" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, @@ -215,6 +216,14 @@ export interface IStartupMetrics { */ readonly ellapsedWorkspaceStorageInit: number; + /** + * The time it took to init the storage database connection from the workbench. + * + * * Happens in the renderer-process + * * Measured with the `code/willInitStorage` and `code/didInitStorage` performance marks. + */ + readonly ellapsedStorageInit: number; + /** * The time it took to initialize the workspace and configuration service. * @@ -514,6 +523,7 @@ export abstract class AbstractTimerService implements ITimerService { ellapsedWindowLoadToRequire: this._marks.getDuration('code/willOpenNewWindow', 'code/willLoadWorkbenchMain'), ellapsedRequire: this._marks.getDuration('code/willLoadWorkbenchMain', 'code/didLoadWorkbenchMain'), ellapsedWaitForShellEnv: this._marks.getDuration('code/willWaitForShellEnv', 'code/didWaitForShellEnv'), + ellapsedStorageInit: this._marks.getDuration('code/willInitStorage', 'code/didInitStorage'), ellapsedWorkspaceStorageInit: this._marks.getDuration('code/willInitWorkspaceStorage', 'code/didInitWorkspaceStorage'), ellapsedWorkspaceServiceInit: this._marks.getDuration('code/willInitWorkspaceService', 'code/didInitWorkspaceService'), ellapsedRequiredUserDataInit: this._marks.getDuration('code/willInitRequiredUserData', 'code/didInitRequiredUserData'), From 5236d3446048c8c08c9ceb46e1b63d438ab5bd75 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 15 Feb 2021 11:40:21 +0100 Subject: [PATCH 131/325] run active editor test only when having focus --- .../vscode-api-tests/src/singlefolder-tests/window.test.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts index 65fd89d3b96..615bb79ac6b 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts @@ -150,6 +150,13 @@ suite('vscode API - window', () => { }); test('active editor not always correct... #49125', async function () { + + if (!window.state.focused) { + // no focus! + this.skip(); + return; + } + if (process.env['BUILD_SOURCEVERSION']) { this.skip(); return; From 196bf678a152024ff55edeb493733dd929adfdfd Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 15 Feb 2021 11:44:51 +0100 Subject: [PATCH 132/325] reset dirty state when reverting a notebook, update extension host when dirty state of a notebook (working copy) changes --- .../notebook.document.test.ts | 27 +++++++++---------- extensions/vscode-api-tests/src/utils.ts | 4 +++ .../api/browser/mainThreadNotebook.ts | 21 ++++++++++++++- .../workbench/api/common/extHost.protocol.ts | 1 + .../workbench/api/common/extHostNotebook.ts | 9 ++++++- .../notebook/common/notebookEditorModel.ts | 1 + 6 files changed, 47 insertions(+), 16 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts index cf9bd87bd24..4e126b0d475 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import * as vscode from 'vscode'; -import { createRandomFile, disposeAll, asPromise, closeAllEditors, assertNoRpc } from '../utils'; +import * as utils from '../utils'; suite('Notebook Document', function () { @@ -33,14 +33,13 @@ suite('Notebook Document', function () { const disposables: vscode.Disposable[] = []; suiteTeardown(async function () { - assertNoRpc(); - await vscode.commands.executeCommand('workbench.action.files.saveAll'); - await closeAllEditors(); - disposeAll(disposables); + await utils.revertAllDirty(); + await utils.closeAllEditors(); + utils.disposeAll(disposables); disposables.length = 0; for (let doc of vscode.notebook.notebookDocuments) { - assert.strictEqual(doc.isDirty, false) + assert.strictEqual(doc.isDirty, false, doc.uri.toString()); } }); @@ -64,7 +63,7 @@ suite('Notebook Document', function () { }); test('document basics', async function () { - const uri = await createRandomFile(undefined, undefined, '.nbdtest'); + const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest'); const notebook = await vscode.notebook.openNotebookDocument(uri); assert.strictEqual(notebook.uri.toString(), uri.toString()); @@ -76,9 +75,9 @@ suite('Notebook Document', function () { }); test('notebook open/close, notebook ready when cell-document open event is fired', async function () { - const uri = await createRandomFile(undefined, undefined, '.nbdtest'); + const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest'); let didHappen = false; - const p = asPromise(vscode.workspace.onDidOpenTextDocument).then(doc => { + const p = utils.asPromise(vscode.workspace.onDidOpenTextDocument).then(doc => { if (doc.uri.scheme !== 'vscode-notebook-cell') { return; } @@ -96,9 +95,9 @@ suite('Notebook Document', function () { }); test('notebook open/close, all cell-documents are ready', async function () { - const uri = await createRandomFile(undefined, undefined, '.nbdtest'); + const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest'); - const p = asPromise(vscode.notebook.onDidOpenNotebookDocument).then(notebook => { + const p = utils.asPromise(vscode.notebook.onDidOpenNotebookDocument).then(notebook => { for (let cell of notebook.cells) { const doc = vscode.workspace.textDocuments.find(doc => doc.uri.toString() === cell.uri.toString()); assert.ok(doc); @@ -116,7 +115,7 @@ suite('Notebook Document', function () { test('workspace edit API (replaceCells)', async function () { - const uri = await createRandomFile(undefined, undefined, '.nbdtest'); + const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest'); const document = await vscode.notebook.openNotebookDocument(uri); assert.strictEqual(document.cells.length, 1); @@ -192,7 +191,7 @@ suite('Notebook Document', function () { }); test('workspace edit API (replaceCells, event)', async function () { - const uri = await createRandomFile(undefined, undefined, '.nbdtest'); + const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest'); const document = await vscode.notebook.openNotebookDocument(uri); assert.strictEqual(document.cells.length, 1); @@ -211,7 +210,7 @@ suite('Notebook Document', function () { source: 'new_code' }]); - const event = asPromise(vscode.notebook.onDidChangeNotebookCells); + const event = utils.asPromise(vscode.notebook.onDidChangeNotebookCells); const success = await vscode.workspace.applyEdit(edit); assert.strictEqual(success, true); diff --git a/extensions/vscode-api-tests/src/utils.ts b/extensions/vscode-api-tests/src/utils.ts index a102e7d2329..4bddd45a5e3 100644 --- a/extensions/vscode-api-tests/src/utils.ts +++ b/extensions/vscode-api-tests/src/utils.ts @@ -48,6 +48,10 @@ export function closeAllEditors(): Thenable { return vscode.commands.executeCommand('workbench.action.closeAllEditors'); } +export function saveAllEditors(): Thenable { + return vscode.commands.executeCommand('workbench.action.files.saveAll'); +} + export async function revertAllDirty(): Promise { return vscode.commands.executeCommand('_workbench.revertAllDirty'); } diff --git a/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts index 871641799f6..5866a81d96a 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -10,7 +10,8 @@ import { Emitter } from 'vs/base/common/event'; import { IRelativePattern } from 'vs/base/common/glob'; import { combinedDisposable, Disposable, DisposableStore, dispose, IDisposable, IReference } from 'vs/base/common/lifecycle'; import { ResourceMap } from 'vs/base/common/map'; -import { IExtUri } from 'vs/base/common/resources'; +import { Schemas } from 'vs/base/common/network'; +import { IExtUri, isEqual } from 'vs/base/common/resources'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -30,6 +31,7 @@ import { IEditorGroup, IEditorGroupsService, preferredSideBySideGroupDirection } import { openEditorWith } from 'vs/workbench/services/editor/common/editorOpenWith'; import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; +import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, INotebookCellStatusBarEntryDto, INotebookDocumentsAndEditorsDelta, INotebookDocumentShowOptions, INotebookModelAddedData, MainContext, MainThreadNotebookShape, NotebookEditorRevealType, NotebookExtensionDescription } from '../common/extHost.protocol'; class DocumentAndEditorState { @@ -121,6 +123,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo constructor( extHostContext: IExtHostContext, + @IWorkingCopyService private readonly _workingCopyService: IWorkingCopyService, @INotebookService private _notebookService: INotebookService, @IConfigurationService private readonly _configurationService: IConfigurationService, @IEditorService private readonly _editorService: IEditorService, @@ -202,6 +205,22 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo } registerListeners() { + + // forward changes to dirty state + // todo@bpasero this seem way too complicated... is there an easy way to + // the actual resource from a working copy? + this._register(this._workingCopyService.onDidChangeDirty(e => { + if (e.resource.scheme !== Schemas.vscodeNotebook) { + return; + } + for (const notebook of this._notebookService.getNotebookTextModels()) { + if (isEqual(notebook.uri.with({ scheme: Schemas.vscodeNotebook }), e.resource)) { + this._proxy.$acceptDirtyStateChanged(notebook.uri, e.isDirty()); + break; + } + } + })); + this._notebookService.listNotebookEditors().forEach((e) => { this._addNotebookEditor(e); }); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index a55a0c041a1..40b4891d0a6 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1803,6 +1803,7 @@ export interface ExtHostNotebookShape { $acceptNotebookActiveKernelChange(event: { uri: UriComponents, providerHandle: number | undefined, kernelFriendlyId: string | undefined }): void; $onDidReceiveMessage(editorId: string, rendererId: string | undefined, message: unknown): void; $acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEventDto, isDirty: boolean): void; + $acceptDirtyStateChanged(uriComponents: UriComponents, isDirty: boolean): void; $acceptModelSaved(uriComponents: UriComponents): void; $acceptEditorPropertiesChanged(id: string, data: INotebookEditorPropertiesChangeData): void; $acceptDocumentPropertiesChanged(uriComponents: UriComponents, data: INotebookDocumentPropertiesChangeData): void; diff --git a/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts index 40ff93d7dd5..2e76b5fe7c9 100644 --- a/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -578,7 +578,14 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN } } - public $acceptModelSaved(uriComponents: UriComponents): void { + $acceptDirtyStateChanged(resource: UriComponents, isDirty: boolean): void { + const document = this._documents.get(URI.revive(resource)); + if (document) { + document.acceptModelChanged({ rawEvents: [], versionId: document.notebookDocument.version }, isDirty); + } + } + + $acceptModelSaved(uriComponents: UriComponents): void { const document = this._documents.get(URI.revive(uriComponents)); if (document) { // this.$acceptDirtyStateChanged(uriComponents, false); diff --git a/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts b/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts index 1ad9b60a8b6..583dad5a8cf 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts @@ -125,6 +125,7 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM async revert(options?: IRevertOptions | undefined): Promise { if (options?.soft) { await this._backupFileService.discardBackup(this.resource); + this.setDirty(false); return; } From cc4d7e8a11adf1c893fe151b07f595216d149219 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 15 Feb 2021 11:52:14 +0100 Subject: [PATCH 133/325] update (restore) language test for new cells --- .../src/singlefolder-tests/notebook.test.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts index 7db8c7784d6..b437120c23c 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts @@ -6,7 +6,7 @@ import 'mocha'; import * as assert from 'assert'; import * as vscode from 'vscode'; -import { createRandomFile, asPromise, disposeAll, closeAllEditors } from '../utils'; +import { createRandomFile, asPromise, disposeAll, closeAllEditors, revertAllDirty } from '../utils'; // Since `workbench.action.splitEditor` command does await properly // Notebook editor/document events are not guaranteed to be sent to the ext host when promise resolves @@ -78,9 +78,11 @@ suite('Notebook API tests', function () { const disposables: vscode.Disposable[] = []; suiteTeardown(async function () { - disposeAll(disposables); - await vscode.commands.executeCommand('workbench.action.files.saveAll'); + await revertAllDirty(); await closeAllEditors(); + + disposeAll(disposables); + disposables.length = 0; }); suiteSetup(function () { @@ -1400,12 +1402,9 @@ suite('Notebook API tests', function () { assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.document.getText(), 'var abc = 0;'); - // todo@jrieken enforce a kernel (how) and test that its language is picked - // assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.language, 'typescript'); - // no kernel -> no default language assert.strictEqual(vscode.window.activeNotebookEditor!.kernel, undefined); - assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.language, 'plaintext'); + assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.language, 'typescript'); await vscode.commands.executeCommand('vscode.openWith', resource, 'default'); assert.strictEqual(vscode.window.activeTextEditor?.document.uri.path, resource.path); From 88089d3f204c8367376e3e0729e4382ff9146172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Mon, 15 Feb 2021 12:04:31 +0100 Subject: [PATCH 134/325] fix terrapin failures not reporting --- build/azure-pipelines/darwin/product-build-darwin.yml | 1 + build/azure-pipelines/linux/product-build-alpine.yml | 1 + build/azure-pipelines/linux/product-build-linux.yml | 1 + build/azure-pipelines/product-compile.yml | 1 + build/azure-pipelines/web/product-build-web.yml | 1 + build/azure-pipelines/win32/product-build-win32.yml | 6 ++++-- 6 files changed, 9 insertions(+), 2 deletions(-) diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index a34ae1c4247..1f3cba946bd 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -71,6 +71,7 @@ steps: condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true')) - script: | + set -e npx https://aka.ms/enablesecurefeed standAlone timeoutInMinutes: 5 condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), eq(variables['ENABLE_TERRAPIN'], 'true')) diff --git a/build/azure-pipelines/linux/product-build-alpine.yml b/build/azure-pipelines/linux/product-build-alpine.yml index a2bbb119bfb..7e3aea8d231 100644 --- a/build/azure-pipelines/linux/product-build-alpine.yml +++ b/build/azure-pipelines/linux/product-build-alpine.yml @@ -69,6 +69,7 @@ steps: displayName: Extract node_modules cache - script: | + set -e npx https://aka.ms/enablesecurefeed standAlone timeoutInMinutes: 5 condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), eq(variables['ENABLE_TERRAPIN'], 'true')) diff --git a/build/azure-pipelines/linux/product-build-linux.yml b/build/azure-pipelines/linux/product-build-linux.yml index 9a42f058155..1d26cee26f4 100644 --- a/build/azure-pipelines/linux/product-build-linux.yml +++ b/build/azure-pipelines/linux/product-build-linux.yml @@ -67,6 +67,7 @@ steps: condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), eq(variables['VSCODE_ARCH'], 'x64')) - script: | + set -e npx https://aka.ms/enablesecurefeed standAlone timeoutInMinutes: 5 condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), eq(variables['ENABLE_TERRAPIN'], 'true')) diff --git a/build/azure-pipelines/product-compile.yml b/build/azure-pipelines/product-compile.yml index 08e3f694520..7855cde1663 100644 --- a/build/azure-pipelines/product-compile.yml +++ b/build/azure-pipelines/product-compile.yml @@ -50,6 +50,7 @@ steps: displayName: Extract node_modules cache - script: | + set -e npx https://aka.ms/enablesecurefeed standAlone timeoutInMinutes: 5 condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), eq(variables['ENABLE_TERRAPIN'], 'true')) diff --git a/build/azure-pipelines/web/product-build-web.yml b/build/azure-pipelines/web/product-build-web.yml index 05aa68fe126..0a8e1c36a88 100644 --- a/build/azure-pipelines/web/product-build-web.yml +++ b/build/azure-pipelines/web/product-build-web.yml @@ -60,6 +60,7 @@ steps: displayName: Extract node_modules cache - script: | + set -e npx https://aka.ms/enablesecurefeed standAlone timeoutInMinutes: 5 condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), eq(variables['ENABLE_TERRAPIN'], 'true')) diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index 035580035b0..7076ebf13b0 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -65,8 +65,10 @@ steps: condition: and(succeeded(), eq(variables.NODE_MODULES_RESTORED, 'true')) displayName: Extract node_modules cache - - script: | - npx https://aka.ms/enablesecurefeed standAlone + - powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { npx https://aka.ms/enablesecurefeed standAlone } timeoutInMinutes: 5 condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), eq(variables['ENABLE_TERRAPIN'], 'true')) displayName: Switch to Terrapin packages From 50bb1cf1a4da4668ce650161b39cafc9cf8e8fb9 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 15 Feb 2021 12:18:19 +0100 Subject: [PATCH 135/325] storage - do not init at random (fix tests on windows) --- src/vs/platform/storage/electron-main/storageMainService.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/vs/platform/storage/electron-main/storageMainService.ts b/src/vs/platform/storage/electron-main/storageMainService.ts index 38e8d235a33..7ed969b0bd2 100644 --- a/src/vs/platform/storage/electron-main/storageMainService.ts +++ b/src/vs/platform/storage/electron-main/storageMainService.ts @@ -48,11 +48,6 @@ export class StorageMainService implements IStorageMainService { const globalStorage = new GlobalStorageMain(this.logService, this.environmentService); - // Trigger init of global storage directly from here - // so that we can be ready for access when the window - // needs it (prevents waterfall of initialization) - globalStorage.initialize(); - return globalStorage; } From ac5b7117ec410194814ff92be79254ebc4389dfe Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 15 Feb 2021 12:52:54 +0100 Subject: [PATCH 136/325] assert no rpc in notebook doc test --- .../src/singlefolder-tests/notebook.document.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts index 4e126b0d475..3a2c081f1d5 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts @@ -33,6 +33,7 @@ suite('Notebook Document', function () { const disposables: vscode.Disposable[] = []; suiteTeardown(async function () { + utils.assertNoRpc(); await utils.revertAllDirty(); await utils.closeAllEditors(); utils.disposeAll(disposables); From 114bac541eba442ef8b6c81e6d409337f8430ac2 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 15 Feb 2021 13:25:02 +0100 Subject: [PATCH 137/325] storage - bring back logging support --- .../sharedProcess/sharedProcessMain.ts | 4 +-- .../electron-sandbox/storageService2.ts | 26 ++++++++++++------- .../electron-browser/desktop.main.ts | 5 ++-- .../electron-sandbox/desktop.main.ts | 4 +-- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index fe2cb6adcae..f60f74463ca 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -59,7 +59,6 @@ import { LoggerService } from 'vs/platform/log/node/loggerService'; import { UserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSyncLog'; import { UserDataAutoSyncService } from 'vs/platform/userDataSync/electron-sandbox/userDataAutoSyncService'; import { NativeStorageService2 } from 'vs/platform/storage/electron-sandbox/storageService2'; -import { StorageDatabaseChannelClient } from 'vs/platform/storage/common/storageIpc'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { GlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService'; import { UserDataSyncResourceEnablementService } from 'vs/platform/userDataSync/common/userDataSyncResourceEnablementService'; @@ -173,8 +172,7 @@ class SharedProcessMain extends Disposable { await configurationService.initialize(); // Storage (global access only) - const storageDatabaseClient = new StorageDatabaseChannelClient(mainProcessService.getChannel('storage'), undefined); - const storageService = new NativeStorageService2(storageDatabaseClient.globalStorage, undefined, environmentService); + const storageService = new NativeStorageService2(undefined, mainProcessService, environmentService); services.set(IStorageService, storageService); await storageService.initialize(); diff --git a/src/vs/platform/storage/electron-sandbox/storageService2.ts b/src/vs/platform/storage/electron-sandbox/storageService2.ts index 97fc6da4e21..b2dd29e21f2 100644 --- a/src/vs/platform/storage/electron-sandbox/storageService2.ts +++ b/src/vs/platform/storage/electron-sandbox/storageService2.ts @@ -5,30 +5,37 @@ import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { StorageScope, WillSaveStateReason, logStorage, AbstractStorageService } from 'vs/platform/storage/common/storage'; -import { Storage, IStorageDatabase, IStorage } from 'vs/base/parts/storage/common/storage'; +import { Storage, IStorage } from 'vs/base/parts/storage/common/storage'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces'; +import { IEmptyWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier, IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces'; import { assertIsDefined } from 'vs/base/common/types'; import { Promises, RunOnceScheduler, runWhenIdle } from 'vs/base/common/async'; import { mark } from 'vs/base/common/performance'; +import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services'; +import { StorageDatabaseChannelClient } from 'vs/platform/storage/common/storageIpc'; +import { joinPath } from 'vs/base/common/resources'; export class NativeStorageService2 extends AbstractStorageService { - private readonly globalStorage = new Storage(this.globalStorageDatabase); - private readonly workspaceStorage = this.workspaceStorageDatabase ? new Storage(this.workspaceStorageDatabase) : undefined; + private readonly globalStorage: IStorage; + private readonly workspaceStorage: IStorage | undefined; private initializePromise: Promise | undefined; - private readonly periodicFlushScheduler = this._register(new RunOnceScheduler(() => this.doFlushWhenIdle(), 60000 /* every minute */)); + private readonly periodicFlushScheduler = this._register(new RunOnceScheduler(() => this.doFlushWhenIdle(), 60 * 1000 /* every minute */)); private runWhenIdleDisposable: IDisposable | undefined = undefined; constructor( - private globalStorageDatabase: IStorageDatabase, - private workspaceStorageDatabase: IStorageDatabase | undefined, - @IEnvironmentService private readonly environmentService: IEnvironmentService + private workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined, + mainProcessService: IMainProcessService, + private readonly environmentService: IEnvironmentService ) { super(); + const storageDataBaseClient = new StorageDatabaseChannelClient(mainProcessService.getChannel('storage'), workspace); + this.globalStorage = new Storage(storageDataBaseClient.globalStorage); + this.workspaceStorage = storageDataBaseClient.workspaceStorage ? new Storage(storageDataBaseClient.workspaceStorage) : undefined; + this.registerListeners(); } @@ -139,7 +146,8 @@ export class NativeStorageService2 extends AbstractStorageService { this.globalStorage.items, this.workspaceStorage ? this.workspaceStorage.items : new Map(), this.environmentService.globalStorageHome.fsPath, - /* this.workspaceStoragePath || */ ''); + this.workspace ? joinPath(this.environmentService.workspaceStorageHome, this.workspace.id, 'state.vscdb').fsPath : '' + ); } async migrate(toWorkspace: IWorkspaceInitializationPayload): Promise { diff --git a/src/vs/workbench/electron-browser/desktop.main.ts b/src/vs/workbench/electron-browser/desktop.main.ts index 411501667ec..057696c9420 100644 --- a/src/vs/workbench/electron-browser/desktop.main.ts +++ b/src/vs/workbench/electron-browser/desktop.main.ts @@ -324,12 +324,11 @@ class DesktopMain extends Disposable { } private async createStorageService(payload: IWorkspaceInitializationPayload, logService: ILogService, mainProcessService: IMainProcessService): Promise { - const storageDataBaseClient = new StorageDatabaseChannelClient(mainProcessService.getChannel('storage'), payload); - let storageService: NativeStorageService | NativeStorageService2; if (this.configuration.enableExperimentalMainProcessWorkspaceStorage) { - storageService = new NativeStorageService2(storageDataBaseClient.globalStorage, storageDataBaseClient.workspaceStorage, this.environmentService); + storageService = new NativeStorageService2(payload, mainProcessService, this.environmentService); } else { + const storageDataBaseClient = new StorageDatabaseChannelClient(mainProcessService.getChannel('storage'), payload); storageService = new NativeStorageService(storageDataBaseClient.globalStorage, logService, this.environmentService); } diff --git a/src/vs/workbench/electron-sandbox/desktop.main.ts b/src/vs/workbench/electron-sandbox/desktop.main.ts index 6edfbc6d1d4..14d55ac5c31 100644 --- a/src/vs/workbench/electron-sandbox/desktop.main.ts +++ b/src/vs/workbench/electron-sandbox/desktop.main.ts @@ -18,7 +18,6 @@ import { isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IWorkspaceIni import { ILoggerService, ILogService } from 'vs/platform/log/common/log'; import { NativeStorageService2 } from 'vs/platform/storage/electron-sandbox/storageService2'; import { Schemas } from 'vs/base/common/network'; -import { StorageDatabaseChannelClient } from 'vs/platform/storage/common/storageIpc'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { IStorageService } from 'vs/platform/storage/common/storage'; @@ -297,8 +296,7 @@ class DesktopMain extends Disposable { } private async createStorageService(payload: IWorkspaceInitializationPayload, mainProcessService: IMainProcessService): Promise { - const storageDataBaseClient = new StorageDatabaseChannelClient(mainProcessService.getChannel('storage'), payload); - const storageService = new NativeStorageService2(storageDataBaseClient.globalStorage, storageDataBaseClient.workspaceStorage, this.environmentService); + const storageService = new NativeStorageService2(payload, mainProcessService, this.environmentService); try { await storageService.initialize(); From 4d89ae10ff8b1de9342803d8ee088d1cef4f6438 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Mon, 15 Feb 2021 12:57:02 +0100 Subject: [PATCH 138/325] fix #116523 --- build/gulpfile.vscode.js | 1 + 1 file changed, 1 insertion(+) diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 7f52a5d99a2..e3ca3514bb6 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -284,6 +284,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op let result = all .pipe(util.skipDirectories()) .pipe(util.fixWin32DirectoryPermissions()) + .pipe(filter(['**', '!**/.github/**'], { dot: true })) // https://github.com/microsoft/vscode/issues/116523 .pipe(electron(_.extend({}, config, { platform, arch: arch === 'armhf' ? 'arm' : arch, ffmpegChromium: true }))) .pipe(filter(['**', '!LICENSE', '!LICENSES.chromium.html', '!version'], { dot: true })); From 965518f9a98e35149842af4464c8715481f47ac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Mon, 15 Feb 2021 13:39:41 +0100 Subject: [PATCH 139/325] fixes #116558 --- src/vs/base/browser/ui/sash/sash.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/vs/base/browser/ui/sash/sash.ts b/src/vs/base/browser/ui/sash/sash.ts index f82138b8626..2fe3fc2bb33 100644 --- a/src/vs/base/browser/ui/sash/sash.ts +++ b/src/vs/base/browser/ui/sash/sash.ts @@ -398,13 +398,21 @@ export class Sash extends Disposable { })); } - private static onMouseEnter(sash: Sash): void { + private static onMouseEnter(sash: Sash, fromLinkedSash: boolean = false): void { sash.hoverDelayer.trigger(() => sash.el.classList.add('hover')); + + if (!fromLinkedSash && sash.linkedSash) { + Sash.onMouseEnter(sash.linkedSash); + } } - private static onMouseLeave(sash: Sash): void { + private static onMouseLeave(sash: Sash, fromLinkedSash: boolean = false): void { sash.hoverDelayer.cancel(); sash.el.classList.remove('hover'); + + if (!fromLinkedSash && sash.linkedSash) { + Sash.onMouseLeave(sash.linkedSash); + } } layout(): void { From c9886c394626b45d1a890f987142486301ee9a62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Mon, 15 Feb 2021 13:40:42 +0100 Subject: [PATCH 140/325] missing recursion break --- src/vs/base/browser/ui/sash/sash.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/base/browser/ui/sash/sash.ts b/src/vs/base/browser/ui/sash/sash.ts index 2fe3fc2bb33..bceaf6e4e9b 100644 --- a/src/vs/base/browser/ui/sash/sash.ts +++ b/src/vs/base/browser/ui/sash/sash.ts @@ -402,7 +402,7 @@ export class Sash extends Disposable { sash.hoverDelayer.trigger(() => sash.el.classList.add('hover')); if (!fromLinkedSash && sash.linkedSash) { - Sash.onMouseEnter(sash.linkedSash); + Sash.onMouseEnter(sash.linkedSash, true); } } @@ -411,7 +411,7 @@ export class Sash extends Disposable { sash.el.classList.remove('hover'); if (!fromLinkedSash && sash.linkedSash) { - Sash.onMouseLeave(sash.linkedSash); + Sash.onMouseLeave(sash.linkedSash, true); } } From 5c330b06d4df1e2c7b17b629b7b31df4b85efea5 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 15 Feb 2021 13:50:41 +0100 Subject: [PATCH 141/325] cells are editable --- .vscode/notebooks/my-work.github-issues | 27 ++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/.vscode/notebooks/my-work.github-issues b/.vscode/notebooks/my-work.github-issues index fb59e914e78..1502c29db16 100644 --- a/.vscode/notebooks/my-work.github-issues +++ b/.vscode/notebooks/my-work.github-issues @@ -8,7 +8,8 @@ { "kind": 2, "language": "github-issues", - "value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog\n\n// current milestone name\n$milestone=milestone:\"February 2021\"" + "value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog\n\n// current milestone name\n$milestone=milestone:\"February 2021\"", + "editable": true }, { "kind": 1, @@ -19,7 +20,8 @@ { "kind": 2, "language": "github-issues", - "value": "$repos $milestone assignee:@me is:open" + "value": "$repos $milestone assignee:@me is:open", + "editable": true }, { "kind": 1, @@ -36,7 +38,8 @@ { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open label:bug" + "value": "$repos assignee:@me is:open label:bug", + "editable": true }, { "kind": 1, @@ -47,7 +50,8 @@ { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open label:debt OR $repos assignee:@me is:open label:engineering" + "value": "$repos assignee:@me is:open label:debt OR $repos assignee:@me is:open label:engineering", + "editable": true }, { "kind": 1, @@ -58,7 +62,8 @@ { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open label:perf OR $repos assignee:@me is:open label:perf-startup OR $repos assignee:@me is:open label:perf-bloat OR $repos assignee:@me is:open label:freeze-slow-crash-leak" + "value": "$repos assignee:@me is:open label:perf OR $repos assignee:@me is:open label:perf-startup OR $repos assignee:@me is:open label:perf-bloat OR $repos assignee:@me is:open label:freeze-slow-crash-leak", + "editable": true }, { "kind": 1, @@ -69,12 +74,14 @@ { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open label:feature-request milestone:Backlog sort:reactions-+1-desc" + "value": "$repos assignee:@me is:open label:feature-request milestone:Backlog sort:reactions-+1-desc", + "editable": true }, { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open milestone:\"Backlog Candidates\"" + "value": "$repos assignee:@me is:open milestone:\"Backlog Candidates\"", + "editable": true }, { "kind": 1, @@ -91,7 +98,8 @@ { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open type:issue -label:bug -label:\"needs more info\" -label:feature-request -label:under-discussion -label:debt -label:plan-item -label:upstream" + "value": "$repos assignee:@me is:open type:issue -label:bug -label:\"needs more info\" -label:feature-request -label:under-discussion -label:debt -label:plan-item -label:upstream", + "editable": true }, { "kind": 1, @@ -102,6 +110,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open label:\"needs more info\"" + "value": "$repos assignee:@me is:open label:\"needs more info\"", + "editable": true } ] \ No newline at end of file From f3b4f3f6acf9addfcde71165b99315794ee839d8 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 15 Feb 2021 14:11:45 +0100 Subject: [PATCH 142/325] unescape characters that marked escaped, fixes https://github.com/microsoft/vscode/issues/115391 --- src/vs/base/browser/markdownRenderer.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/vs/base/browser/markdownRenderer.ts b/src/vs/base/browser/markdownRenderer.ts index 81457733d22..2feb2ab7f0c 100644 --- a/src/vs/base/browser/markdownRenderer.ts +++ b/src/vs/base/browser/markdownRenderer.ts @@ -383,5 +383,16 @@ export function renderMarkdownAsPlaintext(markdown: IMarkdownString) { if (value.length > 100_000) { value = `${value.substr(0, 100_000)}…`; } - return sanitizeRenderedMarkdown({ isTrusted: false }, marked.parse(value, { renderer })).toString(); + + const unescapeInfo = new Map([ + ['"', ':'], + ['&', '&'], + [''', '\''], + ['<', '<'], + ['>', '>'], + ]); + + const html = marked.parse(value, { renderer }).replace(/&(#\d+|[a-zA-Z]+);/g, m => unescapeInfo.get(m) ?? m); + + return sanitizeRenderedMarkdown({ isTrusted: false }, html).toString(); } From 793371f05595dffe0885c94fc13f787dcc6a9b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Mon, 15 Feb 2021 14:13:24 +0100 Subject: [PATCH 143/325] remove twistie hover feedback --- src/vs/base/browser/ui/list/listWidget.ts | 5 ----- src/vs/platform/theme/common/colorRegistry.ts | 1 - src/vs/platform/theme/common/styler.ts | 4 +--- 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 398ace4b213..74b933a7e18 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -779,10 +779,6 @@ export class DefaultStyleController implements IStyleController { content.push(`.monaco-list${suffix}:not(.drop-target) .monaco-list-row:hover:not(.selected):not(.focused) { background-color: ${styles.listHoverBackground}; }`); } - if (styles.listTwistieHoverBackground) { - content.push(`.monaco-list${suffix}:not(.drop-target) .monaco-tl-twistie:hover::before { background-color: ${styles.listTwistieHoverBackground}; }`); - } - if (styles.listHoverForeground) { content.push(`.monaco-list${suffix} .monaco-list-row:hover:not(.selected):not(.focused) { color: ${styles.listHoverForeground}; }`); } @@ -874,7 +870,6 @@ export interface IListStyles { listInactiveFocusBackground?: Color; listHoverBackground?: Color; listHoverForeground?: Color; - listTwistieHoverBackground?: Color; listDropBackground?: Color; listFocusOutline?: Color; listInactiveFocusOutline?: Color; diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index 8ed02eb2756..6098286d467 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -373,7 +373,6 @@ export const listInactiveFocusBackground = registerColor('list.inactiveFocusBack export const listInactiveFocusOutline = registerColor('list.inactiveFocusOutline', { dark: null, light: null, hc: null }, nls.localize('listInactiveFocusOutline', "List/Tree outline color for the focused item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.")); export const listHoverBackground = registerColor('list.hoverBackground', { dark: '#2A2D2E', light: '#F0F0F0', hc: null }, nls.localize('listHoverBackground', "List/Tree background when hovering over items using the mouse.")); export const listHoverForeground = registerColor('list.hoverForeground', { dark: null, light: null, hc: null }, nls.localize('listHoverForeground', "List/Tree foreground when hovering over items using the mouse.")); -export const listTwistieHoverBackground = registerColor('list.twistieHoverBackground', { dark: transparent(lighten(listHoverBackground, 0.5), 0.7), light: transparent(darken(listHoverBackground, 0.1), 0.7), hc: null }, nls.localize('twistieHoverBackground', "List/Tree background when hovering over a twistie using the mouse.")); export const listDropBackground = registerColor('list.dropBackground', { dark: listFocusBackground, light: listFocusBackground, hc: null }, nls.localize('listDropBackground', "List/Tree drag and drop background when moving items around using the mouse.")); export const listHighlightForeground = registerColor('list.highlightForeground', { dark: '#0097fb', light: '#0066BF', hc: focusBorder }, nls.localize('highlight', 'List/Tree foreground color of the match highlights when searching inside the list/tree.')); export const listInvalidItemForeground = registerColor('list.invalidItemForeground', { dark: '#B89500', light: '#B89500', hc: '#B89500' }, nls.localize('invalidItemForeground', 'List/Tree foreground color for invalid items, for example an unresolved root in explorer.')); diff --git a/src/vs/platform/theme/common/styler.ts b/src/vs/platform/theme/common/styler.ts index 68d7d175e40..02c66cc4325 100644 --- a/src/vs/platform/theme/common/styler.ts +++ b/src/vs/platform/theme/common/styler.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService'; -import { focusBorder, inputBackground, inputForeground, ColorIdentifier, selectForeground, selectBackground, selectListBackground, selectBorder, inputBorder, foreground, editorBackground, contrastBorder, inputActiveOptionBorder, inputActiveOptionBackground, inputActiveOptionForeground, listFocusBackground, listFocusForeground, listActiveSelectionBackground, listActiveSelectionForeground, listInactiveSelectionForeground, listInactiveSelectionBackground, listInactiveFocusBackground, listHoverBackground, listHoverForeground, listTwistieHoverBackground, listDropBackground, pickerGroupBorder, pickerGroupForeground, widgetShadow, inputValidationInfoBorder, inputValidationInfoBackground, inputValidationWarningBorder, inputValidationWarningBackground, inputValidationErrorBorder, inputValidationErrorBackground, activeContrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, ColorFunction, badgeBackground, badgeForeground, progressBarBackground, breadcrumbsForeground, breadcrumbsFocusForeground, breadcrumbsActiveSelectionForeground, breadcrumbsBackground, editorWidgetBorder, inputValidationInfoForeground, inputValidationWarningForeground, inputValidationErrorForeground, menuForeground, menuBackground, menuSelectionForeground, menuSelectionBackground, menuSelectionBorder, menuBorder, menuSeparatorBackground, darken, listFilterWidgetOutline, listFilterWidgetNoMatchesOutline, listFilterWidgetBackground, editorWidgetBackground, treeIndentGuidesStroke, editorWidgetForeground, simpleCheckboxBackground, simpleCheckboxBorder, simpleCheckboxForeground, ColorValue, resolveColorValue, textLinkForeground, problemsWarningIconForeground, problemsErrorIconForeground, problemsInfoIconForeground, buttonSecondaryBackground, buttonSecondaryForeground, buttonSecondaryHoverBackground, listFocusOutline, listInactiveFocusOutline } from 'vs/platform/theme/common/colorRegistry'; +import { focusBorder, inputBackground, inputForeground, ColorIdentifier, selectForeground, selectBackground, selectListBackground, selectBorder, inputBorder, foreground, editorBackground, contrastBorder, inputActiveOptionBorder, inputActiveOptionBackground, inputActiveOptionForeground, listFocusBackground, listFocusForeground, listActiveSelectionBackground, listActiveSelectionForeground, listInactiveSelectionForeground, listInactiveSelectionBackground, listInactiveFocusBackground, listHoverBackground, listHoverForeground, listDropBackground, pickerGroupBorder, pickerGroupForeground, widgetShadow, inputValidationInfoBorder, inputValidationInfoBackground, inputValidationWarningBorder, inputValidationWarningBackground, inputValidationErrorBorder, inputValidationErrorBackground, activeContrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, ColorFunction, badgeBackground, badgeForeground, progressBarBackground, breadcrumbsForeground, breadcrumbsFocusForeground, breadcrumbsActiveSelectionForeground, breadcrumbsBackground, editorWidgetBorder, inputValidationInfoForeground, inputValidationWarningForeground, inputValidationErrorForeground, menuForeground, menuBackground, menuSelectionForeground, menuSelectionBackground, menuSelectionBorder, menuBorder, menuSeparatorBackground, darken, listFilterWidgetOutline, listFilterWidgetNoMatchesOutline, listFilterWidgetBackground, editorWidgetBackground, treeIndentGuidesStroke, editorWidgetForeground, simpleCheckboxBackground, simpleCheckboxBorder, simpleCheckboxForeground, ColorValue, resolveColorValue, textLinkForeground, problemsWarningIconForeground, problemsErrorIconForeground, problemsInfoIconForeground, buttonSecondaryBackground, buttonSecondaryForeground, buttonSecondaryHoverBackground, listFocusOutline, listInactiveFocusOutline } from 'vs/platform/theme/common/colorRegistry'; import { IDisposable } from 'vs/base/common/lifecycle'; import { Color } from 'vs/base/common/color'; import { IThemable, styleFn } from 'vs/base/common/styler'; @@ -221,7 +221,6 @@ export interface IListStyleOverrides extends IStyleOverrides { listInactiveFocusOutline?: ColorIdentifier; listHoverBackground?: ColorIdentifier; listHoverForeground?: ColorIdentifier; - listTwistieHoverBackground?: ColorIdentifier; listDropBackground?: ColorIdentifier; listSelectionOutline?: ColorIdentifier; listHoverOutline?: ColorIdentifier; @@ -250,7 +249,6 @@ export const defaultListStyles: IColorMapping = { listInactiveFocusOutline, listHoverBackground, listHoverForeground, - listTwistieHoverBackground, listDropBackground, listSelectionOutline: activeContrastBorder, listHoverOutline: activeContrastBorder, From 9dca2bed0bb35ddc83e626bc616598ee4f9e2445 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 15 Feb 2021 14:15:57 +0100 Subject: [PATCH 144/325] Fix bug in tree view tests Fixes #113896 --- .../workbench/test/browser/api/extHostTreeViews.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/test/browser/api/extHostTreeViews.test.ts b/src/vs/workbench/test/browser/api/extHostTreeViews.test.ts index 651add03080..22f2eeef016 100644 --- a/src/vs/workbench/test/browser/api/extHostTreeViews.test.ts +++ b/src/vs/workbench/test/browser/api/extHostTreeViews.test.ts @@ -604,7 +604,7 @@ suite('ExtHostTreeView', function () { const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription); return loadCompleteTree('treeDataProvider') .then(() => { - runWithEventMerging((resolve) => { + return runWithEventMerging((resolve) => { tree = { 'a': { 'aa': {}, @@ -633,9 +633,9 @@ suite('ExtHostTreeView', function () { .then(() => { assert.ok(revealTarget.calledOnce); assert.deepStrictEqual('treeDataProvider', revealTarget.args[0][0]); - assert.deepStrictEqual({ handle: '0/0:b/0:bc', label: { label: 'bc' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:b' }, removeUnsetKeys(revealTarget.args[0][1])); - assert.deepStrictEqual([{ handle: '0/0:b', label: { label: 'b' }, collapsibleState: TreeItemCollapsibleState.Collapsed }], (>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg))); - assert.deepStrictEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][3]); + assert.deepStrictEqual({ handle: '0/0:b/0:bc', label: { label: 'bc' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:b' }, removeUnsetKeys(revealTarget.args[0][1].item)); + assert.deepStrictEqual([{ handle: '0/0:b', label: { label: 'b' }, collapsibleState: TreeItemCollapsibleState.Collapsed }], (>revealTarget.args[0][1].parentChain).map(arg => removeUnsetKeys(arg))); + assert.deepStrictEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][2]); }); }); }); From c4c044e20dba1434b61294b426712af47558e976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Mon, 15 Feb 2021 14:29:23 +0100 Subject: [PATCH 145/325] fix quick input inactive focus background color --- src/vs/base/browser/ui/list/listWidget.ts | 6 ++++++ src/vs/base/parts/quickinput/browser/quickInput.ts | 6 +----- src/vs/platform/quickinput/browser/quickInput.ts | 4 ++-- src/vs/platform/theme/common/colorRegistry.ts | 1 + 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 74b933a7e18..d399ef27bd7 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -761,6 +761,11 @@ export class DefaultStyleController implements IStyleController { `); } + if (styles.listInactiveFocusForeground) { + content.push(`.monaco-list${suffix} .monaco-list-row.focused { color: ${styles.listInactiveFocusForeground}; }`); + content.push(`.monaco-list${suffix} .monaco-list-row.focused:hover { color: ${styles.listInactiveFocusForeground}; }`); // overwrite :hover style in this case! + } + if (styles.listInactiveFocusBackground) { content.push(`.monaco-list${suffix} .monaco-list-row.focused { background-color: ${styles.listInactiveFocusBackground}; }`); content.push(`.monaco-list${suffix} .monaco-list-row.focused:hover { background-color: ${styles.listInactiveFocusBackground}; }`); // overwrite :hover style in this case! @@ -867,6 +872,7 @@ export interface IListStyles { listFocusAndSelectionForeground?: Color; listInactiveSelectionBackground?: Color; listInactiveSelectionForeground?: Color; + listInactiveFocusForeground?: Color; listInactiveFocusBackground?: Color; listHoverBackground?: Color; listHoverForeground?: Color; diff --git a/src/vs/base/parts/quickinput/browser/quickInput.ts b/src/vs/base/parts/quickinput/browser/quickInput.ts index 038816012f3..2ab5e7a478d 100644 --- a/src/vs/base/parts/quickinput/browser/quickInput.ts +++ b/src/vs/base/parts/quickinput/browser/quickInput.ts @@ -56,7 +56,7 @@ export interface IQuickInputStyles { countBadge: ICountBadgetyles; button: IButtonStyles; progressBar: IProgressBarStyles; - list: IListStyles & { listInactiveFocusForeground?: Color; pickerGroupBorder?: Color; pickerGroupForeground?: Color; }; + list: IListStyles & { pickerGroupBorder?: Color; pickerGroupForeground?: Color; }; } export interface IQuickInputWidgetStyles { @@ -1706,10 +1706,6 @@ export class QuickInputController extends Disposable { this.ui.list.style(this.styles.list); const content: string[] = []; - if (this.styles.list.listInactiveFocusForeground) { - content.push(`.monaco-list .monaco-list-row.focused { color: ${this.styles.list.listInactiveFocusForeground}; }`); - content.push(`.monaco-list .monaco-list-row.focused:hover { color: ${this.styles.list.listInactiveFocusForeground}; }`); // overwrite :hover style in this case! - } if (this.styles.list.pickerGroupBorder) { content.push(`.quick-input-list .quick-input-list-entry { border-top-color: ${this.styles.list.pickerGroupBorder}; }`); } diff --git a/src/vs/platform/quickinput/browser/quickInput.ts b/src/vs/platform/quickinput/browser/quickInput.ts index 86f5ddaf348..299eb02fd91 100644 --- a/src/vs/platform/quickinput/browser/quickInput.ts +++ b/src/vs/platform/quickinput/browser/quickInput.ts @@ -7,7 +7,7 @@ import { IQuickInputService, IQuickPickItem, IPickOptions, IInputOptions, IQuick import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IThemeService, Themable } from 'vs/platform/theme/common/themeService'; -import { inputBackground, inputForeground, inputBorder, inputValidationInfoBackground, inputValidationInfoForeground, inputValidationInfoBorder, inputValidationWarningBackground, inputValidationWarningForeground, inputValidationWarningBorder, inputValidationErrorBackground, inputValidationErrorForeground, inputValidationErrorBorder, badgeBackground, badgeForeground, contrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, progressBarBackground, widgetShadow, listFocusForeground, listFocusBackground, activeContrastBorder, pickerGroupBorder, pickerGroupForeground, quickInputForeground, quickInputBackground, quickInputTitleBackground } from 'vs/platform/theme/common/colorRegistry'; +import { inputBackground, inputForeground, inputBorder, inputValidationInfoBackground, inputValidationInfoForeground, inputValidationInfoBorder, inputValidationWarningBackground, inputValidationWarningForeground, inputValidationWarningBorder, inputValidationErrorBackground, inputValidationErrorForeground, inputValidationErrorBorder, badgeBackground, badgeForeground, contrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, progressBarBackground, widgetShadow, listFocusForeground, listFocusBackground, activeContrastBorder, pickerGroupBorder, pickerGroupForeground, quickInputForeground, quickInputBackground, quickInputTitleBackground, listFocusOutline, quickInputListFocusBackground } from 'vs/platform/theme/common/colorRegistry'; import { CancellationToken } from 'vs/base/common/cancellation'; import { computeStyles } from 'vs/platform/theme/common/styler'; import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey'; @@ -213,7 +213,7 @@ export class QuickInputService extends Themable implements IQuickInputService { listBackground: quickInputBackground, // Look like focused when inactive. listInactiveFocusForeground: listFocusForeground, - listInactiveFocusBackground: listFocusBackground, + listInactiveFocusBackground: quickInputListFocusBackground, listFocusOutline: activeContrastBorder, listInactiveFocusOutline: activeContrastBorder, pickerGroupBorder, diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index 6098286d467..58b90b849ff 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -288,6 +288,7 @@ export const editorWidgetResizeBorder = registerColor('editorWidget.resizeBorder export const quickInputBackground = registerColor('quickInput.background', { dark: editorWidgetBackground, light: editorWidgetBackground, hc: editorWidgetBackground }, nls.localize('pickerBackground', "Quick picker background color. The quick picker widget is the container for pickers like the command palette.")); export const quickInputForeground = registerColor('quickInput.foreground', { dark: editorWidgetForeground, light: editorWidgetForeground, hc: editorWidgetForeground }, nls.localize('pickerForeground', "Quick picker foreground color. The quick picker widget is the container for pickers like the command palette.")); export const quickInputTitleBackground = registerColor('quickInputTitle.background', { dark: new Color(new RGBA(255, 255, 255, 0.105)), light: new Color(new RGBA(0, 0, 0, 0.06)), hc: '#000000' }, nls.localize('pickerTitleBackground', "Quick picker title background color. The quick picker widget is the container for pickers like the command palette.")); +export const quickInputListFocusBackground = registerColor('quickInput.list.focusBackground', { dark: '#062F4A', light: '#D6EBFF', hc: null }, nls.localize('quickInput.listFocusBackground', "Quick picker background color for the focused item.")); export const pickerGroupForeground = registerColor('pickerGroup.foreground', { dark: '#3794FF', light: '#0066BF', hc: Color.white }, nls.localize('pickerGroupForeground', "Quick picker color for grouping labels.")); export const pickerGroupBorder = registerColor('pickerGroup.border', { dark: '#3F3F46', light: '#CCCEDB', hc: Color.white }, nls.localize('pickerGroupBorder', "Quick picker color for grouping borders.")); From 4077a67914bacb7d85c58f921812fcd01ea3a8b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Mon, 15 Feb 2021 14:29:36 +0100 Subject: [PATCH 146/325] adopt focus border across all core themes --- extensions/theme-abyss/themes/abyss-color-theme.json | 2 +- .../theme-kimbie-dark/themes/kimbie-dark-color-theme.json | 2 +- .../theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json | 2 +- extensions/theme-monokai/themes/monokai-color-theme.json | 2 +- extensions/theme-quietlight/themes/quietlight-color-theme.json | 2 +- extensions/theme-red/themes/Red-color-theme.json | 2 +- .../theme-solarized-dark/themes/solarized-dark-color-theme.json | 2 +- .../themes/solarized-light-color-theme.json | 2 +- .../themes/tomorrow-night-blue-color-theme.json | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/extensions/theme-abyss/themes/abyss-color-theme.json b/extensions/theme-abyss/themes/abyss-color-theme.json index 8e97bbb6dc1..391b5af61b7 100644 --- a/extensions/theme-abyss/themes/abyss-color-theme.json +++ b/extensions/theme-abyss/themes/abyss-color-theme.json @@ -303,7 +303,7 @@ "list.activeSelectionBackground": "#08286b", // "list.activeSelectionForeground": "", - "list.focusBackground": "#08286b", + "quickInput.list.focusBackground": "#08286b", "list.hoverBackground": "#061940", "list.inactiveSelectionBackground": "#152037", "list.dropBackground": "#041D52", diff --git a/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json b/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json index 3453c53dc2b..24ba31854fe 100644 --- a/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json +++ b/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json @@ -10,7 +10,7 @@ "list.highlightForeground": "#e3b583", "list.activeSelectionBackground": "#7c5021", "list.hoverBackground": "#7c502166", - "list.focusBackground": "#7c5021AA", + "quickInput.list.focusBackground": "#7c5021AA", "list.inactiveSelectionBackground": "#645342", "pickerGroup.foreground": "#e3b583", "pickerGroup.border": "#e3b583", diff --git a/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json b/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json index bd8b896c011..9ca62cc15e3 100644 --- a/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json +++ b/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json @@ -3,7 +3,7 @@ "colors": { "dropdown.background": "#525252", "list.activeSelectionBackground": "#707070", - "list.focusBackground": "#707070", + "quickInput.list.focusBackground": "#707070", "list.inactiveSelectionBackground": "#4e4e4e", "list.hoverBackground": "#444444", "list.highlightForeground": "#e58520", diff --git a/extensions/theme-monokai/themes/monokai-color-theme.json b/extensions/theme-monokai/themes/monokai-color-theme.json index 969455d01e3..100d291ddad 100644 --- a/extensions/theme-monokai/themes/monokai-color-theme.json +++ b/extensions/theme-monokai/themes/monokai-color-theme.json @@ -9,7 +9,7 @@ "colors": { "dropdown.background": "#414339", "list.activeSelectionBackground": "#75715E", - "list.focusBackground": "#414339", + "quickInput.list.focusBackground": "#414339", "dropdown.listBackground": "#1e1f1c", "list.inactiveSelectionBackground": "#414339", "list.hoverBackground": "#3e3d32", diff --git a/extensions/theme-quietlight/themes/quietlight-color-theme.json b/extensions/theme-quietlight/themes/quietlight-color-theme.json index e395b99e3eb..376c5fda7a3 100644 --- a/extensions/theme-quietlight/themes/quietlight-color-theme.json +++ b/extensions/theme-quietlight/themes/quietlight-color-theme.json @@ -473,7 +473,7 @@ "pickerGroup.foreground": "#A6B39B", "pickerGroup.border": "#749351", "list.activeSelectionForeground": "#6c6c6c", - "list.focusBackground": "#CADEB9", + "quickInput.list.focusBackground": "#CADEB9", "list.hoverBackground": "#e0e0e0", "list.activeSelectionBackground": "#c4d9b1", "list.inactiveSelectionBackground": "#d3dbcd", diff --git a/extensions/theme-red/themes/Red-color-theme.json b/extensions/theme-red/themes/Red-color-theme.json index 8eeda13456e..c3e728b7f39 100644 --- a/extensions/theme-red/themes/Red-color-theme.json +++ b/extensions/theme-red/themes/Red-color-theme.json @@ -49,7 +49,7 @@ "list.activeSelectionBackground": "#880000", "list.inactiveSelectionBackground": "#770000", "list.dropBackground": "#662222", - "list.focusBackground": "#660000", + "quickInput.list.focusBackground": "#660000", "list.highlightForeground": "#ff4444", "pickerGroup.foreground": "#cc9999", "pickerGroup.border": "#ff000033", diff --git a/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json b/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json index 8a9deb0cd4b..b887521b605 100644 --- a/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json +++ b/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json @@ -350,7 +350,7 @@ "list.activeSelectionBackground": "#005A6F", // "list.activeSelectionForeground": "", - "list.focusBackground": "#005A6F", + "quickInput.list.focusBackground": "#005A6F", "list.hoverBackground": "#004454AA", "list.inactiveSelectionBackground": "#00445488", "list.dropBackground": "#00445488", diff --git a/extensions/theme-solarized-light/themes/solarized-light-color-theme.json b/extensions/theme-solarized-light/themes/solarized-light-color-theme.json index 427b7c3c359..1efe1e000e3 100644 --- a/extensions/theme-solarized-light/themes/solarized-light-color-theme.json +++ b/extensions/theme-solarized-light/themes/solarized-light-color-theme.json @@ -350,7 +350,7 @@ "list.activeSelectionBackground": "#DFCA88", "list.activeSelectionForeground": "#6C6C6C", - "list.focusBackground": "#DFCA8866", + "quickInput.list.focusBackground": "#DFCA8866", "list.hoverBackground": "#DFCA8844", "list.inactiveSelectionBackground": "#D1CBB8", "list.highlightForeground": "#B58900", diff --git a/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-color-theme.json b/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-color-theme.json index 91c135342f1..e4ae768d9f5 100644 --- a/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-color-theme.json +++ b/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-color-theme.json @@ -5,7 +5,7 @@ "errorForeground": "#a92049", "input.background": "#001733", "dropdown.background": "#001733", - "list.focusBackground": "#ffffff60", + "quickInput.list.focusBackground": "#ffffff60", "list.activeSelectionBackground": "#ffffff60", "list.inactiveSelectionBackground": "#ffffff40", "list.hoverBackground": "#ffffff30", From 250c2265459f3bb4b65022e1b678286f804e8fdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Mon, 15 Feb 2021 14:42:28 +0100 Subject: [PATCH 147/325] fix suggest widget styles --- src/vs/editor/contrib/suggest/suggestWidget.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 884207922f2..94135e09b63 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -21,7 +21,7 @@ import { Context as SuggestContext, CompletionItem } from './suggest'; import { CompletionModel } from './completionModel'; import { attachListStyler } from 'vs/platform/theme/common/styler'; import { IThemeService, IColorTheme, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; -import { registerColor, editorWidgetBackground, listFocusBackground, activeContrastBorder, listHighlightForeground, editorForeground, editorWidgetBorder, focusBorder, textLinkForeground, textCodeBlockBackground } from 'vs/platform/theme/common/colorRegistry'; +import { registerColor, editorWidgetBackground, quickInputListFocusBackground, activeContrastBorder, listHighlightForeground, editorForeground, editorWidgetBorder, focusBorder, textLinkForeground, textCodeBlockBackground } from 'vs/platform/theme/common/colorRegistry'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { TimeoutTimer, CancelablePromise, createCancelablePromise, disposableTimeout } from 'vs/base/common/async'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -40,7 +40,7 @@ import { clamp } from 'vs/base/common/numbers'; export const editorSuggestWidgetBackground = registerColor('editorSuggestWidget.background', { dark: editorWidgetBackground, light: editorWidgetBackground, hc: editorWidgetBackground }, nls.localize('editorSuggestWidgetBackground', 'Background color of the suggest widget.')); export const editorSuggestWidgetBorder = registerColor('editorSuggestWidget.border', { dark: editorWidgetBorder, light: editorWidgetBorder, hc: editorWidgetBorder }, nls.localize('editorSuggestWidgetBorder', 'Border color of the suggest widget.')); export const editorSuggestWidgetForeground = registerColor('editorSuggestWidget.foreground', { dark: editorForeground, light: editorForeground, hc: editorForeground }, nls.localize('editorSuggestWidgetForeground', 'Foreground color of the suggest widget.')); -export const editorSuggestWidgetSelectedBackground = registerColor('editorSuggestWidget.selectedBackground', { dark: listFocusBackground, light: listFocusBackground, hc: listFocusBackground }, nls.localize('editorSuggestWidgetSelectedBackground', 'Background color of the selected entry in the suggest widget.')); +export const editorSuggestWidgetSelectedBackground = registerColor('editorSuggestWidget.selectedBackground', { dark: quickInputListFocusBackground, light: quickInputListFocusBackground, hc: quickInputListFocusBackground }, nls.localize('editorSuggestWidgetSelectedBackground', 'Background color of the selected entry in the suggest widget.')); export const editorSuggestWidgetHighlightForeground = registerColor('editorSuggestWidget.highlightForeground', { dark: listHighlightForeground, light: listHighlightForeground, hc: listHighlightForeground }, nls.localize('editorSuggestWidgetHighlightForeground', 'Color of the match highlights in the suggest widget.')); const enum State { From e2d1cfb64a1d1a85ba9f159d4abe7636bfaf1f22 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 15 Feb 2021 15:01:34 +0100 Subject: [PATCH 148/325] make SubmenuItemAction dynamic again --- src/vs/platform/actions/common/actions.ts | 28 ++++++++++------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 9de9273c464..1e2d2df6c2f 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -321,34 +321,30 @@ export class ExecuteCommandAction extends Action { export class SubmenuItemAction extends SubmenuAction { - readonly item: ISubmenuItem; - constructor( - item: ISubmenuItem, - menuService: IMenuService, - contextKeyService: IContextKeyService, - options?: IMenuActionOptions + readonly item: ISubmenuItem, + private readonly _menuService: IMenuService, + private readonly _contextKeyService: IContextKeyService, + private readonly _options?: IMenuActionOptions ) { + super(`submenuitem.${item.submenu.id}`, typeof item.title === 'string' ? item.title : item.title.value, [], 'submenu'); + } + + get actions(): readonly IAction[] { const result: IAction[] = []; - const menu = menuService.createMenu(item.submenu, contextKeyService); - const groups = menu.getActions(options); + const menu = this._menuService.createMenu(this.item.submenu, this._contextKeyService); + const groups = menu.getActions(this._options); menu.dispose(); - - for (let group of groups) { - const [, actions] = group; - + for (const [, actions] of groups) { if (actions.length > 0) { result.push(...actions); result.push(new Separator()); } } - if (result.length) { result.pop(); // remove last separator } - - super(`submenuitem.${item.submenu.id}`, typeof item.title === 'string' ? item.title : item.title.value, result, 'submenu'); - this.item = item; + return result; } } From 59afea597bd88efcee15e93abaebe704d9dab889 Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 15 Feb 2021 15:02:39 +0100 Subject: [PATCH 149/325] explorer: click in empty area -> create a new file fixes #116676 --- .../contrib/files/browser/views/explorerView.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/files/browser/views/explorerView.ts b/src/vs/workbench/contrib/files/browser/views/explorerView.ts index 59b05dd4866..451dcceccff 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerView.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerView.ts @@ -183,7 +183,8 @@ export class ExplorerView extends ViewPane { @IClipboardService private clipboardService: IClipboardService, @IFileService private readonly fileService: IFileService, @IUriIdentityService private readonly uriIdentityService: IUriIdentityService, - @IOpenerService openerService: IOpenerService, + @ICommandService private readonly commandService: ICommandService, + @IOpenerService openerService: IOpenerService ) { super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService); @@ -459,6 +460,13 @@ export class ExplorerView extends ViewPane { } })); + this._register(this.tree.onMouseDblClick(e => { + if (e.element === null) { + // click in empty area -> create a new file #116676 + this.commandService.executeCommand(NEW_FILE_COMMAND_ID); + } + })); + // save view state this._register(this.storageService.onWillSaveState(() => { this.storageService.store(ExplorerView.TREE_VIEW_STATE_STORAGE_KEY, JSON.stringify(this.tree.getViewState()), StorageScope.WORKSPACE, StorageTarget.MACHINE); From 7dc11581e45058e8f9f43a7eec04ac901efab2f6 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 15 Feb 2021 15:09:17 +0100 Subject: [PATCH 150/325] remove unused event --- .../api/common/extHostNotebookDocument.ts | 26 +++++-------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/src/vs/workbench/api/common/extHostNotebookDocument.ts b/src/vs/workbench/api/common/extHostNotebookDocument.ts index 21d2e99a563..0fe42bd9de4 100644 --- a/src/vs/workbench/api/common/extHostNotebookDocument.ts +++ b/src/vs/workbench/api/common/extHostNotebookDocument.ts @@ -8,7 +8,6 @@ import { hash } from 'vs/base/common/hash'; import { Disposable, DisposableStore, dispose } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; import { joinPath } from 'vs/base/common/resources'; -import { ISplice } from 'vs/base/common/sequence'; import { URI } from 'vs/base/common/uri'; import { CellKind, INotebookDocumentPropertiesChangeData } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostDocumentsAndEditors, IExtHostModelAddedData } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; @@ -30,7 +29,7 @@ class RawContentChangeEvent { } } -export class ExtHostCell extends Disposable { +export class ExtHostCell { static asModelAddData(notebook: vscode.NotebookDocument, cell: IMainCellDto): IExtHostModelAddedData { return { @@ -47,11 +46,7 @@ export class ExtHostCell extends Disposable { private _onDidDispose = new Emitter(); readonly onDidDispose: Event = this._onDidDispose.event; - private _onDidChangeOutputs = new Emitter[]>(); - readonly onDidChangeOutputs: Event[]> = this._onDidChangeOutputs.event; - private _outputs: IOutputDto[]; - private _metadata: vscode.NotebookCellMetadata; readonly handle: number; @@ -65,18 +60,18 @@ export class ExtHostCell extends Disposable { private readonly _extHostDocument: ExtHostDocumentsAndEditors, private readonly _cellData: IMainCellDto, ) { - super(); - this.handle = _cellData.handle; this.uri = URI.revive(_cellData.uri); this.cellKind = _cellData.cellKind; - this._outputs = _cellData.outputs; - - this._metadata = _cellData.metadata ?? {}; } + dispose() { + this._onDidDispose.fire(); + this._onDidDispose.dispose(); + } + get cell(): vscode.NotebookCell { if (!this._cell) { const that = this; @@ -100,11 +95,6 @@ export class ExtHostCell extends Disposable { return this._cell; } - dispose() { - super.dispose(); - this._onDidDispose.fire(); - } - setOutputs(newOutputs: IOutputDto[]): void { this._outputs = newOutputs; } @@ -137,10 +127,8 @@ export class ExtHostNotebookDocument extends Disposable { private _cellDisposableMapping = new Map(); private _notebook: vscode.NotebookDocument | undefined; - // private _metadata: Required; - // private _metadataChangeListener: IDisposable; private _versionId = 0; - private _isDirty: boolean = false; + private _isDirty = false; private _backupCounter = 1; private _backup?: vscode.NotebookDocumentBackup; private _disposed = false; From 62d027a713cc25b4d7224957f170aeb793a1b56b Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 15 Feb 2021 15:26:28 +0100 Subject: [PATCH 151/325] more API todos --- src/vs/vscode.proposed.d.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 0122b4e2b2a..7f26c9427ab 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1104,6 +1104,7 @@ declare module 'vscode' { export interface NotebookDocument { readonly uri: Uri; readonly version: number; + // todo@API don't have this... readonly fileName: string; // todo@API should we really expose this? readonly viewType: string; @@ -1322,6 +1323,9 @@ declare module 'vscode' { export const onDidChangeNotebookDocumentMetadata: Event; export const onDidChangeNotebookCells: Event; export const onDidChangeCellOutputs: Event; + + // todo@API we send document close and open events when the language of a document changes and + // I believe we should stick that for cells as well export const onDidChangeCellLanguage: Event; export const onDidChangeCellMetadata: Event; } From 8848ddd9c06aac2918d2bbd37ff3c8eefa7d76eb Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 15 Feb 2021 15:27:19 +0100 Subject: [PATCH 152/325] use metadata classes inside NotebookCell and NotebookDocument --- .../workbench/api/common/extHostNotebook.ts | 2 +- .../api/common/extHostNotebookDocument.ts | 21 +++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts index 2e76b5fe7c9..347418f4927 100644 --- a/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -729,7 +729,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN emitDocumentMetadataChange(event: vscode.NotebookDocumentMetadataChangeEvent): void { that._onDidChangeNotebookDocumentMetadata.fire(event); } - }, viewType, modelData.contentOptions, { ...notebookDocumentMetadataDefaults, ...modelData.metadata }, uri, storageRoot); + }, viewType, modelData.contentOptions, new extHostTypes.NotebookDocumentMetadata().with(modelData.metadata ?? {}), uri, storageRoot); document.acceptModelChanged({ versionId: modelData.versionId, diff --git a/src/vs/workbench/api/common/extHostNotebookDocument.ts b/src/vs/workbench/api/common/extHostNotebookDocument.ts index 0fe42bd9de4..b8a9bc12073 100644 --- a/src/vs/workbench/api/common/extHostNotebookDocument.ts +++ b/src/vs/workbench/api/common/extHostNotebookDocument.ts @@ -12,7 +12,8 @@ import { URI } from 'vs/base/common/uri'; import { CellKind, INotebookDocumentPropertiesChangeData } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostDocumentsAndEditors, IExtHostModelAddedData } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters'; -import { IMainCellDto, IOutputDto, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import * as extHostTypes from 'vs/workbench/api/common/extHostTypes'; +import { IMainCellDto, IOutputDto, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2 } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import * as vscode from 'vscode'; class RawContentChangeEvent { @@ -47,7 +48,7 @@ export class ExtHostCell { readonly onDidDispose: Event = this._onDidDispose.event; private _outputs: IOutputDto[]; - private _metadata: vscode.NotebookCellMetadata; + private _metadata: extHostTypes.NotebookCellMetadata; readonly handle: number; readonly uri: URI; @@ -64,7 +65,7 @@ export class ExtHostCell { this.uri = URI.revive(_cellData.uri); this.cellKind = _cellData.cellKind; this._outputs = _cellData.outputs; - this._metadata = _cellData.metadata ?? {}; + this._metadata = new extHostTypes.NotebookCellMetadata().with(_cellData.metadata ?? {}); } dispose() { @@ -99,8 +100,8 @@ export class ExtHostCell { this._outputs = newOutputs; } - setMetadata(newMetadata: vscode.NotebookCellMetadata): void { - this._metadata = newMetadata; + setMetadata(newMetadata: NotebookCellMetadata): void { + this._metadata = this._metadata.with(newMetadata); } } @@ -138,7 +139,7 @@ export class ExtHostNotebookDocument extends Disposable { private readonly _emitter: INotebookEventEmitter, private readonly _viewType: string, private readonly _contentOptions: vscode.NotebookDocumentContentOptions, - private _metadata: Required, + private _metadata: extHostTypes.NotebookDocumentMetadata, public readonly uri: URI, private readonly _storagePath: URI | undefined ) { @@ -190,11 +191,9 @@ export class ExtHostNotebookDocument extends Disposable { } acceptDocumentPropertiesChanged(data: INotebookDocumentPropertiesChangeData) { - const newMetadata = { - ...notebookDocumentMetadataDefaults, - ...data.metadata - }; - this._metadata = newMetadata; + if (data.metadata) { + this._metadata = this._metadata.with(data.metadata); + } this._emitter.emitDocumentMetadataChange({ document: this.notebookDocument }); } From 58b13a2fd1d32406d8c4b1e220eb9e7947f8af8d Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 15 Feb 2021 15:34:18 +0100 Subject: [PATCH 153/325] Fix too many/wrong port notification Fixes microsoft/vscode-remote-release#4472 --- src/vs/workbench/contrib/remote/browser/remoteExplorer.ts | 3 +++ src/vs/workbench/contrib/remote/browser/urlFinder.ts | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts index f3ba2a45148..a5325de6807 100644 --- a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts +++ b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts @@ -544,6 +544,9 @@ class ProcAutomaticPortForwarding extends Disposable { if (this.initialCandidates.has(address)) { return undefined; } + if (this.notifiedOnly.has(address) || this.autoForwarded.has(address)) { + return undefined; + } const alreadyForwarded = mapHasAddressLocalhostOrAllInterfaces(this.remoteExplorerService.tunnelModel.forwarded, value.host, value.port); if (mapHasAddressLocalhostOrAllInterfaces(this.remoteExplorerService.tunnelModel.detected, value.host, value.port)) { return undefined; diff --git a/src/vs/workbench/contrib/remote/browser/urlFinder.ts b/src/vs/workbench/contrib/remote/browser/urlFinder.ts index cb3c96dc2f1..ba36c2b5414 100644 --- a/src/vs/workbench/contrib/remote/browser/urlFinder.ts +++ b/src/vs/workbench/contrib/remote/browser/urlFinder.ts @@ -104,7 +104,12 @@ export class UrlFinder extends Disposable { if (urlMatches && urlMatches.length > 0) { urlMatches.forEach((match) => { // check if valid url - const serverUrl = new URL(match); + let serverUrl; + try { + serverUrl = new URL(match); + } catch (e) { + // Not a valid URL + } if (serverUrl) { // check if the port is a valid integer value const portMatch = match.match(UrlFinder.extractPortRegex); From d56305b3f9a3244d36b5f16742f22974f39c4560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Mon, 15 Feb 2021 15:40:37 +0100 Subject: [PATCH 154/325] cleanup imports --- src/vs/platform/quickinput/browser/quickInput.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/quickinput/browser/quickInput.ts b/src/vs/platform/quickinput/browser/quickInput.ts index 299eb02fd91..6c54bf00996 100644 --- a/src/vs/platform/quickinput/browser/quickInput.ts +++ b/src/vs/platform/quickinput/browser/quickInput.ts @@ -7,7 +7,7 @@ import { IQuickInputService, IQuickPickItem, IPickOptions, IInputOptions, IQuick import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IThemeService, Themable } from 'vs/platform/theme/common/themeService'; -import { inputBackground, inputForeground, inputBorder, inputValidationInfoBackground, inputValidationInfoForeground, inputValidationInfoBorder, inputValidationWarningBackground, inputValidationWarningForeground, inputValidationWarningBorder, inputValidationErrorBackground, inputValidationErrorForeground, inputValidationErrorBorder, badgeBackground, badgeForeground, contrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, progressBarBackground, widgetShadow, listFocusForeground, listFocusBackground, activeContrastBorder, pickerGroupBorder, pickerGroupForeground, quickInputForeground, quickInputBackground, quickInputTitleBackground, listFocusOutline, quickInputListFocusBackground } from 'vs/platform/theme/common/colorRegistry'; +import { inputBackground, inputForeground, inputBorder, inputValidationInfoBackground, inputValidationInfoForeground, inputValidationInfoBorder, inputValidationWarningBackground, inputValidationWarningForeground, inputValidationWarningBorder, inputValidationErrorBackground, inputValidationErrorForeground, inputValidationErrorBorder, badgeBackground, badgeForeground, contrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, progressBarBackground, widgetShadow, listFocusForeground, activeContrastBorder, pickerGroupBorder, pickerGroupForeground, quickInputForeground, quickInputBackground, quickInputTitleBackground, quickInputListFocusBackground } from 'vs/platform/theme/common/colorRegistry'; import { CancellationToken } from 'vs/base/common/cancellation'; import { computeStyles } from 'vs/platform/theme/common/styler'; import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey'; From 96640b6b875d650100297bdd68f9f362483c14b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Mon, 15 Feb 2021 15:48:06 +0100 Subject: [PATCH 155/325] tree: remove bogus expandOnlyOnDoubleClick --- src/vs/base/browser/ui/tree/abstractTree.ts | 6 ------ src/vs/platform/list/browser/listService.ts | 4 ---- 2 files changed, 10 deletions(-) diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index 3e135b3c8a8..6f644b9c940 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -961,7 +961,6 @@ export interface IAbstractTreeOptionsUpdate extends ITreeRendererOptions { readonly filterOnType?: boolean; readonly smoothScrolling?: boolean; readonly horizontalScrolling?: boolean; - readonly expandOnlyOnDoubleClick?: boolean; readonly expandOnlyOnTwistieClick?: boolean | ((e: any) => boolean); // e is T } @@ -1121,10 +1120,6 @@ class TreeNodeListMouseController extends MouseController< return super.onViewPointer(e); } - if (this.tree.expandOnlyOnDoubleClick && e.browserEvent.detail !== 2 && !onTwistie) { - return super.onViewPointer(e); - } - if (node.collapsible) { const model = ((this.tree as any).model as ITreeModel); // internal const location = model.getNodeLocation(node); @@ -1263,7 +1258,6 @@ export abstract class AbstractTree implements IDisposable get filterOnType(): boolean { return !!this._options.filterOnType; } get onDidChangeTypeFilterPattern(): Event { return this.typeFilterController ? this.typeFilterController.onDidChangePattern : Event.None; } - get expandOnlyOnDoubleClick(): boolean { return this._options.expandOnlyOnDoubleClick ?? false; } get expandOnlyOnTwistieClick(): boolean | ((e: T) => boolean) { return typeof this._options.expandOnlyOnTwistieClick === 'undefined' ? true : this._options.expandOnlyOnTwistieClick; } private readonly _onDidUpdateOptions = new Emitter>(); diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index 127f5ad81bf..b421ee719c6 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -852,7 +852,6 @@ function workbenchTreeDataPreamble(treeExpandMode) === 'doubleClick') } as TOptions }; @@ -952,9 +951,6 @@ class WorkbenchTreeInternals { const horizontalScrolling = configurationService.getValue(horizontalScrollingKey); newOptions = { ...newOptions, horizontalScrolling }; } - if (e.affectsConfiguration(openModeSettingKey)) { - newOptions = { ...newOptions, expandOnlyOnDoubleClick: configurationService.getValue(openModeSettingKey) === 'doubleClick' }; - } if (e.affectsConfiguration(treeExpandMode) && options.expandOnlyOnTwistieClick === undefined) { newOptions = { ...newOptions, expandOnlyOnTwistieClick: configurationService.getValue<'singleClick' | 'doubleClick'>(treeExpandMode) === 'doubleClick' }; } From 2a9b2181ffe7305d10a29ff3d2049e08a995569c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Mon, 15 Feb 2021 15:52:59 +0100 Subject: [PATCH 156/325] improve list settings docs --- src/vs/platform/list/browser/listService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index b421ee719c6..752fdb0e4e1 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -1017,7 +1017,7 @@ configurationRegistry.registerConfiguration({ 'description': localize({ key: 'openModeModifier', comment: ['`singleClick` and `doubleClick` refers to a value the setting can take and should not be localized.'] - }, "Controls how to open items in trees and lists using the mouse (if supported). For parents with children in trees, this setting will control if a single click expands the parent or a double click. Note that some trees and lists might choose to ignore this setting if it is not applicable. ") + }, "Controls how to open items in trees and lists using the mouse (if supported). For parents with children in trees, this setting will control if a single click expands the parent or a double click. Note that some trees and lists might choose to ignore this setting if it is not applicable.") }, [horizontalScrollingKey]: { 'type': 'boolean', @@ -1062,7 +1062,7 @@ configurationRegistry.registerConfiguration({ type: 'string', enum: ['singleClick', 'doubleClick'], default: 'doubleClick', - description: localize('expand mode', "Controls how tree folders are expanded when clicking the folder names."), + description: localize('expand mode', "Controls how tree folders are expanded when clicking the folder names. Note that some trees and lists might choose to ignore this setting if it is not applicable."), } } }); From 7bf4a3d823d16138782b9aaf59c2794b1d582e69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Mon, 15 Feb 2021 15:53:42 +0100 Subject: [PATCH 157/325] fixes #115212 --- src/vs/base/browser/ui/tree/abstractTree.ts | 8 +++++++- src/vs/workbench/contrib/outline/browser/outlinePane.ts | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index 6f644b9c940..af081547c85 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -961,6 +961,7 @@ export interface IAbstractTreeOptionsUpdate extends ITreeRendererOptions { readonly filterOnType?: boolean; readonly smoothScrolling?: boolean; readonly horizontalScrolling?: boolean; + readonly expandOnDoubleClick?: boolean; readonly expandOnlyOnTwistieClick?: boolean | ((e: any) => boolean); // e is T } @@ -1120,6 +1121,10 @@ class TreeNodeListMouseController extends MouseController< return super.onViewPointer(e); } + if (!this.tree.expandOnDoubleClick && e.browserEvent.detail === 2) { + return super.onViewPointer(e); + } + if (node.collapsible) { const model = ((this.tree as any).model as ITreeModel); // internal const location = model.getNodeLocation(node); @@ -1138,7 +1143,7 @@ class TreeNodeListMouseController extends MouseController< protected onDoubleClick(e: IListMouseEvent>): void { const onTwistie = (e.browserEvent.target as HTMLElement).classList.contains('monaco-tl-twistie'); - if (onTwistie) { + if (onTwistie || !this.tree.expandOnDoubleClick) { return; } @@ -1258,6 +1263,7 @@ export abstract class AbstractTree implements IDisposable get filterOnType(): boolean { return !!this._options.filterOnType; } get onDidChangeTypeFilterPattern(): Event { return this.typeFilterController ? this.typeFilterController.onDidChangePattern : Event.None; } + get expandOnDoubleClick(): boolean { return typeof this._options.expandOnDoubleClick === 'undefined' ? true : this._options.expandOnDoubleClick; } get expandOnlyOnTwistieClick(): boolean | ((e: T) => boolean) { return typeof this._options.expandOnlyOnTwistieClick === 'undefined' ? true : this._options.expandOnlyOnTwistieClick; } private readonly _onDidUpdateOptions = new Emitter>(); diff --git a/src/vs/workbench/contrib/outline/browser/outlinePane.ts b/src/vs/workbench/contrib/outline/browser/outlinePane.ts index 5a3c4048178..9ef31066da0 100644 --- a/src/vs/workbench/contrib/outline/browser/outlinePane.ts +++ b/src/vs/workbench/contrib/outline/browser/outlinePane.ts @@ -232,6 +232,7 @@ export class OutlinePane extends ViewPane { ...newOutline.config.options, sorter, openOnSingleClick: true, + expandOnDoubleClick: false, expandOnlyOnTwistieClick: true, multipleSelectionSupport: false, hideTwistiesOfChildlessElements: true, From ebc30d6c92cfab9a0e9571a27490f634ed2853a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Mon, 15 Feb 2021 15:55:25 +0100 Subject: [PATCH 158/325] fixes #116700 --- src/vs/workbench/contrib/outline/browser/outlinePane.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/outline/browser/outlinePane.ts b/src/vs/workbench/contrib/outline/browser/outlinePane.ts index 9ef31066da0..e988a1a3a9d 100644 --- a/src/vs/workbench/contrib/outline/browser/outlinePane.ts +++ b/src/vs/workbench/contrib/outline/browser/outlinePane.ts @@ -231,7 +231,6 @@ export class OutlinePane extends ViewPane { { ...newOutline.config.options, sorter, - openOnSingleClick: true, expandOnDoubleClick: false, expandOnlyOnTwistieClick: true, multipleSelectionSupport: false, From 18c04a5716063d0d7d21adf3e09667db314b37f4 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 15 Feb 2021 15:47:53 +0100 Subject: [PATCH 159/325] make `vscode.NotebookCellRange` a class --- src/vs/vscode.proposed.d.ts | 5 ++-- .../workbench/api/common/extHost.api.impl.ts | 3 +++ .../workbench/api/common/extHost.protocol.ts | 7 +----- .../workbench/api/common/extHostNotebook.ts | 10 ++++---- .../api/common/extHostNotebookEditor.ts | 10 ++++---- .../api/common/extHostTypeConverters.ts | 13 +++++++++- src/vs/workbench/api/common/extHostTypes.ts | 25 +++++++++++++++++++ 7 files changed, 54 insertions(+), 19 deletions(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 7f26c9427ab..6bd29a1c0f9 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1116,13 +1116,14 @@ declare module 'vscode' { } // todo@API maybe have a NotebookCellPosition sibling - // todo@API should be a class - export interface NotebookCellRange { + export class NotebookCellRange { readonly start: number; /** * exclusive */ readonly end: number; + + constructor(start: number, end: number); } export enum NotebookEditorRevealType { diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 09a44ef2b07..b9bacd2d7f6 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -1253,6 +1253,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I // checkProposedApiEnabled(extension); return extHostTypes.TimelineItem; }, + get NotebookCellRange() { + return extHostTypes.NotebookCellRange; + }, get NotebookCellKind() { // checkProposedApiEnabled(extension); return extHostTypes.NotebookCellKind; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 40b4891d0a6..d8dea657c6f 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1731,13 +1731,8 @@ export interface INotebookSelectionChangeEvent { selections: number[]; } -export interface INotebookCellVisibleRange { - start: number; - end: number; -} - export interface INotebookVisibleRangesEvent { - ranges: INotebookCellVisibleRange[]; + ranges: ICellRange[]; } export interface INotebookEditorPropertiesChangeData { diff --git a/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts index 347418f4927..8b5ff7fd411 100644 --- a/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -403,7 +403,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN resolvedOptions = { position: typeConverters.ViewColumn.from(options.viewColumn), preserveFocus: options.preserveFocus, - selection: options.selection, + selection: options.selection && typeConverters.NotebookCellRange.from(options.selection), pinned: typeof options.preview === 'boolean' ? !options.preview : undefined }; } else { @@ -608,7 +608,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN } if (data.visibleRanges) { - editor.editor._acceptVisibleRanges(data.visibleRanges.ranges); + editor.editor._acceptVisibleRanges(data.visibleRanges.ranges.map(typeConverters.NotebookCellRange.to)); this._onDidChangeNotebookEditorVisibleRanges.fire({ notebookEditor: editor.editor, visibleRanges: editor.editor.visibleRanges @@ -643,7 +643,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN } } - private _createExtHostEditor(document: ExtHostNotebookDocument, editorId: string, selections: number[], visibleRanges: vscode.NotebookCellRange[]) { + private _createExtHostEditor(document: ExtHostNotebookDocument, editorId: string, selections: number[], visibleRanges: extHostTypes.NotebookCellRange[]) { const revivedUri = document.uri; let webComm = this._webviewComm.get(editorId); @@ -753,7 +753,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN // create editor if populated if (modelData.attachedEditor) { - this._createExtHostEditor(document, modelData.attachedEditor.id, modelData.attachedEditor.selections, modelData.attachedEditor.visibleRanges); + this._createExtHostEditor(document, modelData.attachedEditor.id, modelData.attachedEditor.selections, modelData.attachedEditor.visibleRanges.map(typeConverters.NotebookCellRange.to)); editorChanged = true; } @@ -773,7 +773,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN const document = this._documents.get(revivedUri); if (document) { - this._createExtHostEditor(document, editorModelData.id, editorModelData.selections, editorModelData.visibleRanges); + this._createExtHostEditor(document, editorModelData.id, editorModelData.selections, editorModelData.visibleRanges.map(typeConverters.NotebookCellRange.to)); editorChanged = true; } } diff --git a/src/vs/workbench/api/common/extHostNotebookEditor.ts b/src/vs/workbench/api/common/extHostNotebookEditor.ts index 9afae7d5be3..7b3105cfb18 100644 --- a/src/vs/workbench/api/common/extHostNotebookEditor.ts +++ b/src/vs/workbench/api/common/extHostNotebookEditor.ts @@ -90,7 +90,7 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook //TODO@rebornix noop setter? selection?: vscode.NotebookCell; - private _visibleRanges: vscode.NotebookCellRange[] = []; + private _visibleRanges: extHostTypes.NotebookCellRange[] = []; private _viewColumn?: vscode.ViewColumn; private _active: boolean = false; private _visible: boolean = false; @@ -153,11 +153,11 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook return this._visibleRanges; } - set visibleRanges(_range: vscode.NotebookCellRange[]) { + set visibleRanges(_range) { throw readonly('visibleRanges'); } - _acceptVisibleRanges(value: vscode.NotebookCellRange[]): void { + _acceptVisibleRanges(value: extHostTypes.NotebookCellRange[]): void { this._visibleRanges = value; } @@ -233,13 +233,13 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook return this._proxy.$trySetDecorations( this.id, - range, + extHostConverter.NotebookCellRange.from(range), decorationType.key ); } revealRange(range: vscode.NotebookCellRange, revealType?: extHostTypes.NotebookEditorRevealType) { - this._proxy.$tryRevealRange(this.id, range, revealType || extHostTypes.NotebookEditorRevealType.Default); + this._proxy.$tryRevealRange(this.id, extHostConverter.NotebookCellRange.from(range), revealType ?? extHostTypes.NotebookEditorRevealType.Default); } async postMessage(message: any): Promise { diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index e838b45bfb9..674ab28bdbf 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -31,7 +31,7 @@ import { coalesce, isNonEmptyArray } from 'vs/base/common/arrays'; import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions'; import { CommandsConverter } from 'vs/workbench/api/common/extHostCommands'; import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook'; -import { CellEditType, CellKind, ICellDto2, INotebookDecorationRenderOptions, IOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellEditType, CellKind, ICellDto2, ICellRange, INotebookDecorationRenderOptions, IOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { ITestItem, ITestState } from 'vs/workbench/contrib/testing/common/testCollection'; export interface PositionLike { @@ -1344,6 +1344,17 @@ export namespace LanguageSelector { } } +export namespace NotebookCellRange { + + export function from(range: vscode.NotebookCellRange): ICellRange { + return { start: range.start, end: range.end }; + } + + export function to(range: ICellRange): types.NotebookCellRange { + return new types.NotebookCellRange(range.start, range.end); + } +} + export namespace NotebookCellKind { export function from(data: vscode.NotebookCellKind): CellKind { switch (data) { diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 96a66824ee6..e7cd5a11828 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -2849,6 +2849,31 @@ export enum ColorThemeKind { //#region Notebook +export class NotebookCellRange { + + private _start: number; + private _end: number; + + get start() { + return this._start; + } + + get end() { + return this._end; + } + + constructor(start: number, end: number) { + if (start < 0) { + throw illegalArgument('start must be positive'); + } + if (end < start) { + throw illegalArgument('end cannot be smaller than start'); + } + this._start = start; + this._end = end; + } +} + export class NotebookCellMetadata { constructor( From 3e2aebd790ce404d3dcc0e3aa3168e857ebd3400 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 15 Feb 2021 16:03:04 +0100 Subject: [PATCH 160/325] Revert "use metadata classes inside NotebookCell and NotebookDocument" This reverts commit 8848ddd9c06aac2918d2bbd37ff3c8eefa7d76eb. --- .../workbench/api/common/extHostNotebook.ts | 2 +- .../api/common/extHostNotebookDocument.ts | 21 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts index 8b5ff7fd411..89388531dd6 100644 --- a/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -729,7 +729,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN emitDocumentMetadataChange(event: vscode.NotebookDocumentMetadataChangeEvent): void { that._onDidChangeNotebookDocumentMetadata.fire(event); } - }, viewType, modelData.contentOptions, new extHostTypes.NotebookDocumentMetadata().with(modelData.metadata ?? {}), uri, storageRoot); + }, viewType, modelData.contentOptions, { ...notebookDocumentMetadataDefaults, ...modelData.metadata }, uri, storageRoot); document.acceptModelChanged({ versionId: modelData.versionId, diff --git a/src/vs/workbench/api/common/extHostNotebookDocument.ts b/src/vs/workbench/api/common/extHostNotebookDocument.ts index b8a9bc12073..0fe42bd9de4 100644 --- a/src/vs/workbench/api/common/extHostNotebookDocument.ts +++ b/src/vs/workbench/api/common/extHostNotebookDocument.ts @@ -12,8 +12,7 @@ import { URI } from 'vs/base/common/uri'; import { CellKind, INotebookDocumentPropertiesChangeData } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostDocumentsAndEditors, IExtHostModelAddedData } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters'; -import * as extHostTypes from 'vs/workbench/api/common/extHostTypes'; -import { IMainCellDto, IOutputDto, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2 } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { IMainCellDto, IOutputDto, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import * as vscode from 'vscode'; class RawContentChangeEvent { @@ -48,7 +47,7 @@ export class ExtHostCell { readonly onDidDispose: Event = this._onDidDispose.event; private _outputs: IOutputDto[]; - private _metadata: extHostTypes.NotebookCellMetadata; + private _metadata: vscode.NotebookCellMetadata; readonly handle: number; readonly uri: URI; @@ -65,7 +64,7 @@ export class ExtHostCell { this.uri = URI.revive(_cellData.uri); this.cellKind = _cellData.cellKind; this._outputs = _cellData.outputs; - this._metadata = new extHostTypes.NotebookCellMetadata().with(_cellData.metadata ?? {}); + this._metadata = _cellData.metadata ?? {}; } dispose() { @@ -100,8 +99,8 @@ export class ExtHostCell { this._outputs = newOutputs; } - setMetadata(newMetadata: NotebookCellMetadata): void { - this._metadata = this._metadata.with(newMetadata); + setMetadata(newMetadata: vscode.NotebookCellMetadata): void { + this._metadata = newMetadata; } } @@ -139,7 +138,7 @@ export class ExtHostNotebookDocument extends Disposable { private readonly _emitter: INotebookEventEmitter, private readonly _viewType: string, private readonly _contentOptions: vscode.NotebookDocumentContentOptions, - private _metadata: extHostTypes.NotebookDocumentMetadata, + private _metadata: Required, public readonly uri: URI, private readonly _storagePath: URI | undefined ) { @@ -191,9 +190,11 @@ export class ExtHostNotebookDocument extends Disposable { } acceptDocumentPropertiesChanged(data: INotebookDocumentPropertiesChangeData) { - if (data.metadata) { - this._metadata = this._metadata.with(data.metadata); - } + const newMetadata = { + ...notebookDocumentMetadataDefaults, + ...data.metadata + }; + this._metadata = newMetadata; this._emitter.emitDocumentMetadataChange({ document: this.notebookDocument }); } From 2ecfd1456620663576ac07ecfc8648c7317d5b43 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 15 Feb 2021 16:08:27 +0100 Subject: [PATCH 161/325] Setting for proc vs output port forwarding Fixes microsoft/vscode-remote-release#4274 --- .../contrib/remote/browser/remoteExplorer.ts | 11 +++++++---- .../contrib/remote/common/remote.contribution.ts | 10 ++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts index a5325de6807..89a5e8545f4 100644 --- a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts +++ b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts @@ -219,10 +219,13 @@ export class AutomaticPortForwarding extends Disposable implements IWorkbenchCon this._register(new OutputAutomaticPortForwarding(terminalService, notificationService, openerService, externalOpenerService, remoteExplorerService, configurationService, debugService, tunnelService, remoteAgentService, hostService, false)); } else if (environment?.os === OperatingSystem.Linux) { - this._register(new ProcAutomaticPortForwarding(configurationService, remoteExplorerService, notificationService, - openerService, externalOpenerService, tunnelService, hostService)); + const useProc = (this.configurationService.getValue('remote.autoForwardPortsSource') === 'process'); + if (useProc) { + this._register(new ProcAutomaticPortForwarding(configurationService, remoteExplorerService, notificationService, + openerService, externalOpenerService, tunnelService, hostService)); + } this._register(new OutputAutomaticPortForwarding(terminalService, notificationService, openerService, externalOpenerService, - remoteExplorerService, configurationService, debugService, tunnelService, remoteAgentService, hostService, true)); + remoteExplorerService, configurationService, debugService, tunnelService, remoteAgentService, hostService, useProc)); } }); } @@ -435,7 +438,7 @@ class OutputAutomaticPortForwarding extends Disposable { } this.urlFinder = this._register(new UrlFinder(this.terminalService, this.debugService)); this._register(this.urlFinder.onDidMatchLocalUrl(async (localUrl) => { - if (mapHasAddressLocalhostOrAllInterfaces(this.remoteExplorerService.tunnelModel.forwarded, localUrl.host, localUrl.port)) { + if (mapHasAddressLocalhostOrAllInterfaces(this.remoteExplorerService.tunnelModel.detected, localUrl.host, localUrl.port)) { return; } if (this.portsAttributes.getAttributes(localUrl.port)?.onAutoForward === OnPortForward.Ignore) { diff --git a/src/vs/workbench/contrib/remote/common/remote.contribution.ts b/src/vs/workbench/contrib/remote/common/remote.contribution.ts index 043cd4876ad..395e5c7cce5 100644 --- a/src/vs/workbench/contrib/remote/common/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/common/remote.contribution.ts @@ -134,6 +134,16 @@ Registry.as(ConfigurationExtensions.Configuration) markdownDescription: localize('remote.autoForwardPorts', "When enabled, new running processes are detected and ports that they listen on are automatically forwarded."), default: true }, + 'remote.autoForwardPortsSource': { + type: 'string', + markdownDescription: localize('remote.autoForwardPortsSource', "Sets the source from which ports are automatically forwarded when `remote.autoForwardPorts` is true. Requires a reload to take effect."), + enum: ['process', 'output'], + enumDescriptions: [ + localize('remote.autoForwardPortsSource.process', "Ports will be automatically forwarded when discovered by watching for processes that are started and include a port."), + localize('remote.autoForwardPortsSource.output', "Ports will be automatically forwarded when discovered by reading terminal and debug output. Not all processes that use ports will print to the integrated terminal or debug console, so some ports will be missed. Ports forwarded based on output will not be \"un-forwarded\" until reload or until the port is closed by the user in the Ports view.") + ], + default: 'process' + }, // Consider making changes to extensions\configuration-editing\schemas\devContainer.schema.src.json // and extensions\configuration-editing\schemas\attachContainer.schema.json // to keep in sync with devcontainer.json schema. From 8fe9b7c5ec9ff9f996dfe286c497fbb10a012296 Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 15 Feb 2021 16:13:46 +0100 Subject: [PATCH 162/325] Fix that keybindings editor input actions can not be triggered via keyboard fixes #116688 --- src/vs/base/browser/ui/checkbox/checkbox.ts | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/vs/base/browser/ui/checkbox/checkbox.ts b/src/vs/base/browser/ui/checkbox/checkbox.ts index cd9e4a2718c..485d85d16d4 100644 --- a/src/vs/base/browser/ui/checkbox/checkbox.ts +++ b/src/vs/base/browser/ui/checkbox/checkbox.ts @@ -76,6 +76,26 @@ export class CheckboxActionViewItem extends BaseActionViewItem { } } + focus(): void { + if (this.checkbox) { + this.checkbox.domNode.tabIndex = 0; + this.checkbox.focus(); + } + } + + blur(): void { + if (this.checkbox) { + this.checkbox.domNode.tabIndex = -1; + this.checkbox.domNode.blur(); + } + } + + setFocusable(focusable: boolean): void { + if (this.checkbox) { + this.checkbox.domNode.tabIndex = focusable ? 0 : -1; + } + } + dispose(): void { this.disposables.dispose(); super.dispose(); @@ -191,7 +211,6 @@ export class Checkbox extends Widget { } enable(): void { - this.domNode.tabIndex = 0; this.domNode.setAttribute('aria-disabled', String(false)); } From 762dc9eeea6ceb43195838c36a5f53fa8394ffed Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 15 Feb 2021 16:30:59 +0100 Subject: [PATCH 163/325] action bar: In case an action got disabled and it was last focused in the action bar We need to reset the tabIndex to be set on the first enabled item --- .../browser/ui/actionbar/actionViewItems.ts | 8 +++++++ src/vs/base/browser/ui/actionbar/actionbar.ts | 21 +++++++++++++++++-- src/vs/base/browser/ui/checkbox/checkbox.ts | 4 ++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/vs/base/browser/ui/actionbar/actionViewItems.ts b/src/vs/base/browser/ui/actionbar/actionViewItems.ts index 3d8ddb9c78c..582761b27e1 100644 --- a/src/vs/base/browser/ui/actionbar/actionViewItems.ts +++ b/src/vs/base/browser/ui/actionbar/actionViewItems.ts @@ -181,6 +181,10 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem { } } + get isFocusable(): boolean { + return this.element?.tabIndex === 0; + } + setFocusable(focusable: boolean): void { if (this.element) { this.element.tabIndex = focusable ? 0 : -1; @@ -288,6 +292,10 @@ export class ActionViewItem extends BaseActionViewItem { } } + get isFocusable(): boolean { + return this.label?.tabIndex === 0; + } + setFocusable(focusable: boolean): void { if (this.label) { this.label.tabIndex = focusable ? 0 : -1; diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index 45afd63c40a..3f5402971bc 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./actionbar'; -import { Disposable, dispose } from 'vs/base/common/lifecycle'; -import { IAction, IActionRunner, ActionRunner, IRunEvent, Separator, IActionViewItem, IActionViewItemProvider } from 'vs/base/common/actions'; +import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { IAction, IActionRunner, ActionRunner, IRunEvent, Separator, IActionViewItem, IActionViewItemProvider, Action } from 'vs/base/common/actions'; import * as DOM from 'vs/base/browser/dom'; import * as types from 'vs/base/common/types'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; @@ -82,6 +82,8 @@ export class ActionBar extends Disposable implements IActionRunner { private _onBeforeRun = this._register(new Emitter()); readonly onBeforeRun = this._onBeforeRun.event; + private actionChangeListeners: IDisposable[] = []; + constructor(container: HTMLElement, options: IActionBarOptions = {}) { super(); @@ -318,6 +320,17 @@ export class ActionBar extends Disposable implements IActionRunner { item.setActionContext(this.context); item.render(actionViewItemElement); + this.actionChangeListeners.push(action instanceof Action ? action.onDidChange(e => { + // In case an action got disabled and it was last focused in the action bar + // We need to reset the tabIndex to be set on the first enabled item + if (e.enabled === false && item instanceof BaseActionViewItem && item.isFocusable) { + const firstEnabled = this.viewItems.find(vi => vi instanceof BaseActionViewItem && vi.isEnabled()); + if (firstEnabled instanceof BaseActionViewItem) { + firstEnabled.setFocusable(true); + } + } + }) : Disposable.None); + if (this.focusable && this.viewItems.every(i => !i.isEnabled()) && item instanceof BaseActionViewItem && item.isEnabled()) { // We need to allow for the first enabled item to be focused on using tab navigation #106441 item.setFocusable(true); @@ -366,12 +379,15 @@ export class ActionBar extends Disposable implements IActionRunner { if (index >= 0 && index < this.viewItems.length) { this.actionsList.removeChild(this.actionsList.childNodes[index]); dispose(this.viewItems.splice(index, 1)); + dispose(this.actionChangeListeners.splice(index, 1)); this._actionIds.splice(index, 1); } } clear(): void { dispose(this.viewItems); + dispose(this.actionChangeListeners); + this.actionChangeListeners = []; this.viewItems = []; this._actionIds = []; DOM.clearNode(this.actionsList); @@ -513,6 +529,7 @@ export class ActionBar extends Disposable implements IActionRunner { dispose(): void { dispose(this.viewItems); + dispose(this.actionChangeListeners); this.viewItems = []; this._actionIds = []; diff --git a/src/vs/base/browser/ui/checkbox/checkbox.ts b/src/vs/base/browser/ui/checkbox/checkbox.ts index 485d85d16d4..037ddbba862 100644 --- a/src/vs/base/browser/ui/checkbox/checkbox.ts +++ b/src/vs/base/browser/ui/checkbox/checkbox.ts @@ -90,6 +90,10 @@ export class CheckboxActionViewItem extends BaseActionViewItem { } } + get isFocusable(): boolean { + return this.checkbox?.domNode.tabIndex === 0; + } + setFocusable(focusable: boolean): void { if (this.checkbox) { this.checkbox.domNode.tabIndex = focusable ? 0 : -1; From f2a491fbc834c8db50325ca6c6f1bc1a7f373992 Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 15 Feb 2021 16:53:59 +0100 Subject: [PATCH 164/325] customSelectBox: do not buble key down and key up events to not conflict with action bar fixes #116693 --- src/vs/base/browser/ui/selectBox/selectBoxCustom.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts index 841f2ee44b0..9a2fab22e13 100644 --- a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts +++ b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts @@ -736,8 +736,8 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.Enter).on(e => this.onEnter(e), this)); this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.Escape).on(e => this.onEscape(e), this)); - this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.UpArrow).on(this.onUpArrow, this)); - this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.DownArrow).on(this.onDownArrow, this)); + this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.UpArrow).on(e => this.onUpArrow(e), this)); + this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.DownArrow).on(e => this.onDownArrow(e), this)); this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.PageDown).on(this.onPageDown, this)); this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.PageUp).on(this.onPageUp, this)); this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.Home).on(this.onHome, this)); @@ -916,8 +916,9 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi } // List navigation - have to handle a disabled option (jump over) - private onDownArrow(): void { + private onDownArrow(e: StandardKeyboardEvent): void { if (this.selected < this.options.length - 1) { + dom.EventHelper.stop(e, true); // Skip disabled options const nextOptionDisabled = this.options[this.selected + 1].isDisabled; @@ -937,8 +938,9 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi } } - private onUpArrow(): void { + private onUpArrow(e: StandardKeyboardEvent): void { if (this.selected > 0) { + dom.EventHelper.stop(e, true); // Skip disabled options const previousOptionDisabled = this.options[this.selected - 1].isDisabled; if (previousOptionDisabled && this.selected > 1) { From 5f48de03e6c49a2638b3cace9721c4f98baa334e Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 15 Feb 2021 16:54:24 +0100 Subject: [PATCH 165/325] use metadata classes for cell and notebook document implementation, https://github.com/microsoft/vscode/issues/116333 --- .../workbench/api/common/extHostNotebook.ts | 2 +- .../api/common/extHostNotebookDocument.ts | 13 ++-- .../api/common/extHostTypeConverters.ts | 59 ++++++++++++------- 3 files changed, 47 insertions(+), 27 deletions(-) diff --git a/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts index 89388531dd6..6b995a33914 100644 --- a/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -729,7 +729,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN emitDocumentMetadataChange(event: vscode.NotebookDocumentMetadataChangeEvent): void { that._onDidChangeNotebookDocumentMetadata.fire(event); } - }, viewType, modelData.contentOptions, { ...notebookDocumentMetadataDefaults, ...modelData.metadata }, uri, storageRoot); + }, viewType, modelData.contentOptions, typeConverters.NotebookDocumentMetadata.to(modelData.metadata ?? {}), uri, storageRoot); document.acceptModelChanged({ versionId: modelData.versionId, diff --git a/src/vs/workbench/api/common/extHostNotebookDocument.ts b/src/vs/workbench/api/common/extHostNotebookDocument.ts index 0fe42bd9de4..3e9e9e41a85 100644 --- a/src/vs/workbench/api/common/extHostNotebookDocument.ts +++ b/src/vs/workbench/api/common/extHostNotebookDocument.ts @@ -12,6 +12,7 @@ import { URI } from 'vs/base/common/uri'; import { CellKind, INotebookDocumentPropertiesChangeData } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostDocumentsAndEditors, IExtHostModelAddedData } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters'; +import * as extHostTypes from 'vs/workbench/api/common/extHostTypes'; import { IMainCellDto, IOutputDto, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import * as vscode from 'vscode'; @@ -47,7 +48,7 @@ export class ExtHostCell { readonly onDidDispose: Event = this._onDidDispose.event; private _outputs: IOutputDto[]; - private _metadata: vscode.NotebookCellMetadata; + private _metadata: extHostTypes.NotebookCellMetadata; readonly handle: number; readonly uri: URI; @@ -64,7 +65,7 @@ export class ExtHostCell { this.uri = URI.revive(_cellData.uri); this.cellKind = _cellData.cellKind; this._outputs = _cellData.outputs; - this._metadata = _cellData.metadata ?? {}; + this._metadata = extHostTypeConverters.NotebookCellMetadata.to(_cellData.metadata ?? {}); } dispose() { @@ -99,8 +100,8 @@ export class ExtHostCell { this._outputs = newOutputs; } - setMetadata(newMetadata: vscode.NotebookCellMetadata): void { - this._metadata = newMetadata; + setMetadata(newMetadata: NotebookCellMetadata): void { + this._metadata = extHostTypeConverters.NotebookCellMetadata.to(newMetadata); } } @@ -138,7 +139,7 @@ export class ExtHostNotebookDocument extends Disposable { private readonly _emitter: INotebookEventEmitter, private readonly _viewType: string, private readonly _contentOptions: vscode.NotebookDocumentContentOptions, - private _metadata: Required, + private _metadata: extHostTypes.NotebookDocumentMetadata, public readonly uri: URI, private readonly _storagePath: URI | undefined ) { @@ -194,7 +195,7 @@ export class ExtHostNotebookDocument extends Disposable { ...notebookDocumentMetadataDefaults, ...data.metadata }; - this._metadata = newMetadata; + this._metadata = this._metadata.with(newMetadata); this._emitter.emitDocumentMetadataChange({ document: this.notebookDocument }); } diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 674ab28bdbf..910683b56be 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -31,7 +31,7 @@ import { coalesce, isNonEmptyArray } from 'vs/base/common/arrays'; import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions'; import { CommandsConverter } from 'vs/workbench/api/common/extHostCommands'; import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook'; -import { CellEditType, CellKind, ICellDto2, ICellRange, INotebookDecorationRenderOptions, IOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import * as notebooks from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { ITestItem, ITestState } from 'vs/workbench/contrib/testing/common/testCollection'; export interface PositionLike { @@ -509,7 +509,7 @@ export namespace TextEdit { } export namespace WorkspaceEdit { - export function from(value: vscode.WorkspaceEdit, documents?: ExtHostDocumentsAndEditors, notebooks?: ExtHostNotebookController): extHostProtocol.IWorkspaceEditDto { + export function from(value: vscode.WorkspaceEdit, documents?: ExtHostDocumentsAndEditors, extHostNotebooks?: ExtHostNotebookController): extHostProtocol.IWorkspaceEditDto { const result: extHostProtocol.IWorkspaceEditDto = { edits: [] }; @@ -544,7 +544,7 @@ export namespace WorkspaceEdit { resource: entry.uri, edit: entry.edit, notebookMetadata: entry.notebookMetadata, - notebookVersionId: notebooks?.lookupNotebookDocument(entry.uri)?.notebookDocument.version + notebookVersionId: extHostNotebooks?.lookupNotebookDocument(entry.uri)?.notebookDocument.version }); } else if (entry._type === types.FileEditType.CellOutput) { @@ -554,7 +554,7 @@ export namespace WorkspaceEdit { metadata: entry.metadata, resource: entry.uri, edit: { - editType: CellEditType.Output, + editType: notebooks.CellEditType.Output, index: entry.index, append: entry.append, outputs: entry.newOutputs.map(NotebookCellOutput.from) @@ -568,7 +568,7 @@ export namespace WorkspaceEdit { metadata: entry.metadata, resource: entry.uri, edit: { - editType: CellEditType.Metadata, + editType: notebooks.CellEditType.Metadata, index: entry.index, metadata: entry.newMetadata } @@ -579,9 +579,9 @@ export namespace WorkspaceEdit { _type: extHostProtocol.WorkspaceEditType.Cell, metadata: entry.metadata, resource: entry.uri, - notebookVersionId: notebooks?.lookupNotebookDocument(entry.uri)?.notebookDocument.version, + notebookVersionId: extHostNotebooks?.lookupNotebookDocument(entry.uri)?.notebookDocument.version, edit: { - editType: CellEditType.Replace, + editType: notebooks.CellEditType.Replace, index: entry.index, count: entry.count, cells: entry.cells.map(NotebookCellData.from) @@ -593,7 +593,7 @@ export namespace WorkspaceEdit { metadata: entry.metadata, resource: entry.uri, edit: { - editType: CellEditType.OutputItems, + editType: notebooks.CellEditType.OutputItems, index: entry.index, outputId: entry.outputId, items: entry.newOutputItems?.map(item => ({ mime: item.mime, value: item.value, metadata: item.metadata })) || [], @@ -1346,31 +1346,50 @@ export namespace LanguageSelector { export namespace NotebookCellRange { - export function from(range: vscode.NotebookCellRange): ICellRange { + export function from(range: vscode.NotebookCellRange): notebooks.ICellRange { return { start: range.start, end: range.end }; } - export function to(range: ICellRange): types.NotebookCellRange { + export function to(range: notebooks.ICellRange): types.NotebookCellRange { return new types.NotebookCellRange(range.start, range.end); } } +export namespace NotebookCellMetadata { + + export function to(data: vscode.NotebookCellMetadata): types.NotebookCellMetadata { + return new types.NotebookCellMetadata(data.editable, data.breakpointMargin, data.runnable, data.hasExecutionOrder, data.executionOrder, data.runStartTime, data.runStartTime, data.statusMessage, data.lastRunDuration, data.inputCollapsed, data.outputCollapsed, data.custom); + } +} + +export namespace NotebookDocumentMetadata { + + export function from(data: types.NotebookDocumentMetadata): notebooks.NotebookDocumentMetadata { + return data; + } + + export function to(data: vscode.NotebookDocumentMetadata): types.NotebookDocumentMetadata { + return new types.NotebookDocumentMetadata(data.editable, data.runnable, data.cellEditable, data.cellRunnable, data.cellHasExecutionOrder, data.displayOrder, data.custom, data.runState, data.trusted); + } + +} + export namespace NotebookCellKind { - export function from(data: vscode.NotebookCellKind): CellKind { + export function from(data: vscode.NotebookCellKind): notebooks.CellKind { switch (data) { case types.NotebookCellKind.Markdown: - return CellKind.Markdown; + return notebooks.CellKind.Markdown; case types.NotebookCellKind.Code: default: - return CellKind.Code; + return notebooks.CellKind.Code; } } - export function to(data: CellKind): vscode.NotebookCellKind { + export function to(data: notebooks.CellKind): vscode.NotebookCellKind { switch (data) { - case CellKind.Markdown: + case notebooks.CellKind.Markdown: return types.NotebookCellKind.Markdown; - case CellKind.Code: + case notebooks.CellKind.Code: default: return types.NotebookCellKind.Code; } @@ -1379,7 +1398,7 @@ export namespace NotebookCellKind { export namespace NotebookCellData { - export function from(data: vscode.NotebookCellData): ICellDto2 { + export function from(data: vscode.NotebookCellData): notebooks.ICellDto2 { return { cellKind: NotebookCellKind.from(data.cellKind), language: data.language, @@ -1397,7 +1416,7 @@ export namespace NotebookCellData { } export namespace NotebookCellOutput { - export function from(output: types.NotebookCellOutput): IOutputDto { + export function from(output: types.NotebookCellOutput): notebooks.IOutputDto { const data = Object.create(null); const custom = Object.create(null); @@ -1418,7 +1437,7 @@ export namespace NotebookCellOutput { }; } - export function to(output: IOutputDto): vscode.NotebookCellOutput { + export function to(output: notebooks.IOutputDto): vscode.NotebookCellOutput { const items: types.NotebookCellOutputItem[] = output.outputs.map(op => new types.NotebookCellOutputItem(op.mime, op.value, op.metadata)); return new types.NotebookCellOutput(items, output.outputId); } @@ -1499,7 +1518,7 @@ export namespace NotebookExclusiveDocumentPattern { } export namespace NotebookDecorationRenderOptions { - export function from(options: vscode.NotebookDecorationRenderOptions): INotebookDecorationRenderOptions { + export function from(options: vscode.NotebookDecorationRenderOptions): notebooks.INotebookDecorationRenderOptions { return { backgroundColor: options.backgroundColor, borderColor: options.borderColor, From 5901b6a4ea192ac3fe4fb9242b1fc2f1a93f826d Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 15 Feb 2021 17:07:42 +0100 Subject: [PATCH 166/325] storage - move lifecycle into service --- src/vs/code/electron-main/app.ts | 4 +-- .../storage/browser/storageService.ts | 16 ++++----- .../storage/electron-main/storageMain.ts | 12 ++++++- .../electron-main/storageMainService.ts | 6 ++-- .../electron-main/storageMainService.test.ts | 33 ++++++++++++++++--- 5 files changed, 52 insertions(+), 19 deletions(-) diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 918d2fb505d..c9aa9a1384e 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -580,9 +580,7 @@ export class CodeApplication extends Disposable { services.set(IExtensionUrlTrustService, new SyncDescriptor(ExtensionUrlTrustService)); // Storage - const storageMainService = new StorageMainService(this.logService, this.environmentService); - services.set(IStorageMainService, storageMainService); - this.lifecycleMainService.onWillShutdown(e => e.join(storageMainService.globalStorage.close())); + services.set(IStorageMainService, new SyncDescriptor(StorageMainService)); // Backups const backupMainService = new BackupMainService(this.environmentService, this.configurationService, this.logService); diff --git a/src/vs/platform/storage/browser/storageService.ts b/src/vs/platform/storage/browser/storageService.ts index d7c9c986d84..0776161e830 100644 --- a/src/vs/platform/storage/browser/storageService.ts +++ b/src/vs/platform/storage/browser/storageService.ts @@ -14,7 +14,7 @@ import { URI } from 'vs/base/common/uri'; import { joinPath } from 'vs/base/common/resources'; import { runWhenIdle, RunOnceScheduler, Promises } from 'vs/base/common/async'; import { VSBuffer } from 'vs/base/common/buffer'; -import { assertIsDefined, assertAllDefined } from 'vs/base/common/types'; +import { assertIsDefined } from 'vs/base/common/types'; export class BrowserStorageService extends AbstractStorageService { @@ -131,14 +131,12 @@ export class BrowserStorageService extends AbstractStorageService { } async logStorage(): Promise { - const [globalStorage, workspaceStorage, globalStorageFile, workspaceStorageFile] = assertAllDefined(this.globalStorage, this.workspaceStorage, this.globalStorageFile, this.workspaceStorageFile); - - const result = await Promise.all([ - globalStorage.items, - workspaceStorage.items - ]); - - return logStorage(result[0], result[1], globalStorageFile.toString(), workspaceStorageFile.toString()); + return logStorage( + assertIsDefined(this.globalStorage).items, + assertIsDefined(this.workspaceStorage).items, + assertIsDefined(this.globalStorageFile).toString(), + assertIsDefined(this.workspaceStorageFile).toString() + ); } async migrate(toWorkspace: IWorkspaceInitializationPayload): Promise { diff --git a/src/vs/platform/storage/electron-main/storageMain.ts b/src/vs/platform/storage/electron-main/storageMain.ts index 18494b1b00b..eb462d73cd1 100644 --- a/src/vs/platform/storage/electron-main/storageMain.ts +++ b/src/vs/platform/storage/electron-main/storageMain.ts @@ -16,6 +16,7 @@ import { IS_NEW_KEY } from 'vs/platform/storage/common/storage'; import { currentSessionDateStorageKey, firstSessionDateStorageKey, instanceStorageKey, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry'; import { generateUuid } from 'vs/base/common/uuid'; import { IEmptyWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; /** * Provides access to global and workspace storage from the @@ -197,9 +198,18 @@ export class GlobalStorageMain extends BaseStorageMain implements IStorageMain { constructor( logService: ILogService, - private readonly environmentService: IEnvironmentService + private readonly environmentService: IEnvironmentService, + private readonly lifecycleMainService: ILifecycleMainService ) { super(logService); + + this.registerListeners(); + } + + private registerListeners(): void { + + // Lifecycle + this.lifecycleMainService.onWillShutdown(e => e.join(this.close())); } protected async doInitialize(): Promise { diff --git a/src/vs/platform/storage/electron-main/storageMainService.ts b/src/vs/platform/storage/electron-main/storageMainService.ts index 7ed969b0bd2..832943ebb04 100644 --- a/src/vs/platform/storage/electron-main/storageMainService.ts +++ b/src/vs/platform/storage/electron-main/storageMainService.ts @@ -6,6 +6,7 @@ import { once } from 'vs/base/common/functional'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { ILogService } from 'vs/platform/log/common/log'; import { GlobalStorageMain, IStorageMain, WorkspaceStorageMain } from 'vs/platform/storage/electron-main/storageMain'; import { IEmptyWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; @@ -33,7 +34,8 @@ export class StorageMainService implements IStorageMainService { constructor( @ILogService private readonly logService: ILogService, - @IEnvironmentService private readonly environmentService: IEnvironmentService + @IEnvironmentService private readonly environmentService: IEnvironmentService, + @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService ) { } @@ -46,7 +48,7 @@ export class StorageMainService implements IStorageMainService { return this.globalStorage; // only once } - const globalStorage = new GlobalStorageMain(this.logService, this.environmentService); + const globalStorage = new GlobalStorageMain(this.logService, this.environmentService, this.lifecycleMainService); return globalStorage; } diff --git a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts index 025bbf6226c..ae3f8165583 100644 --- a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts +++ b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts @@ -16,9 +16,12 @@ import { StorageMainService } from 'vs/platform/storage/electron-main/storageMai import { currentSessionDateStorageKey, firstSessionDateStorageKey, instanceStorageKey } from 'vs/platform/telemetry/common/telemetry'; import { IStorageChangeEvent, IStorageMain } from 'vs/platform/storage/electron-main/storageMain'; import { generateUuid } from 'vs/base/common/uuid'; -import { isWindows } from 'vs/base/common/platform'; import { IS_NEW_KEY } from 'vs/platform/storage/common/storage'; import { joinPath } from 'vs/base/common/resources'; +import { ILifecycleMainService, LifecycleMainPhase, UnloadReason } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; +import { Event } from 'vs/base/common/event'; +import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; +import { ICodeWindow } from 'vs/platform/windows/electron-main/windows'; flakySuite('StorageMainService (native)', function () { @@ -41,6 +44,28 @@ flakySuite('StorageMainService (native)', function () { } } + class StorageTestLifecycleMainService implements ILifecycleMainService { + + _serviceBrand: undefined; + + onBeforeShutdown = Event.None; + onWillShutdown = Event.None; + onBeforeWindowClose = Event.None; + onBeforeWindowUnload = Event.None; + + wasRestarted = false; + quitRequested = false; + + phase = LifecycleMainPhase.Ready; + + async reload(window: ICodeWindow, cli?: NativeParsedArgs): Promise { } + async unload(window: ICodeWindow, reason: UnloadReason): Promise { return true; } + relaunch(options?: { addArgs?: string[] | undefined; removeArgs?: string[] | undefined; }): void { } + async quit(fromUpdate?: boolean): Promise { return true; } + async kill(code?: number): Promise { } + async when(phase: LifecycleMainPhase): Promise { } + } + let testDir: string; let environmentService: StorageTestEnvironmentService; @@ -126,17 +151,17 @@ flakySuite('StorageMainService (native)', function () { test('basics (global)', function () { return testStorage(() => { - const storageMainService = new StorageMainService(new NullLogService(), environmentService); + const storageMainService = new StorageMainService(new NullLogService(), environmentService, new StorageTestLifecycleMainService()); return storageMainService.globalStorage; }, true); }); test('basics (workspace)', function () { - const workspace = { id: generateUuid(), uri: URI.file(isWindows ? 'C:\\testWorkspace' : '/testWorkspace') }; + const workspace = { id: generateUuid() }; return testStorage(() => { - const storageMainService = new StorageMainService(new NullLogService(), environmentService); + const storageMainService = new StorageMainService(new NullLogService(), environmentService, new StorageTestLifecycleMainService()); return storageMainService.workspaceStorage(workspace); }, false); From 2e53ffced96d221dfcadbeefb5fd90be8d9f61dc Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 15 Feb 2021 17:16:16 +0100 Subject: [PATCH 167/325] add precondition to exec'ish cell commands --- .../contrib/notebook/browser/contrib/coreActions.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts index 9705204ab05..6e8611e59ec 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts @@ -21,7 +21,7 @@ import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput'; import { CATEGORIES } from 'vs/workbench/common/actions'; -import { BaseCellRenderTemplate, CellEditState, CellFocusMode, EXECUTE_CELL_COMMAND_ID, EXPAND_CELL_CONTENT_COMMAND_ID, IActiveNotebookEditor, ICellViewModel, INotebookEditor, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_EDITOR_FOCUSED, NOTEBOOK_CELL_HAS_OUTPUTS, NOTEBOOK_CELL_INPUT_COLLAPSED, NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_OUTPUT_COLLAPSED, NOTEBOOK_CELL_TYPE, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_RUNNABLE, NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_OUTPUT_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { BaseCellRenderTemplate, CellEditState, CellFocusMode, EXECUTE_CELL_COMMAND_ID, EXPAND_CELL_CONTENT_COMMAND_ID, IActiveNotebookEditor, ICellViewModel, INotebookEditor, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_EDITOR_FOCUSED, NOTEBOOK_CELL_HAS_OUTPUTS, NOTEBOOK_CELL_INPUT_COLLAPSED, NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_OUTPUT_COLLAPSED, NOTEBOOK_CELL_TYPE, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_RUNNABLE, NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_KERNEL_COUNT, NOTEBOOK_OUTPUT_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { CellEditType, CellKind, ICellEditOperation, ICellRange, INotebookDocumentFilter, isDocumentExcludePattern, NotebookCellMetadata, NotebookCellRunState, NOTEBOOK_EDITOR_CURSOR_BEGIN_END, NOTEBOOK_EDITOR_CURSOR_BOUNDARY, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; @@ -228,10 +228,11 @@ export function getWidgetFromUri(accessor: ServicesAccessor, uri: URI) { return undefined; } -registerAction2(class extends NotebookCellAction { +registerAction2(class ExecuteCell extends NotebookCellAction { constructor() { super({ id: EXECUTE_CELL_COMMAND_ID, + precondition: ContextKeyExpr.greater(NOTEBOOK_KERNEL_COUNT.key, 0), title: localize('notebookActions.execute', "Execute Cell"), keybinding: { when: NOTEBOOK_CELL_LIST_FOCUSED, @@ -312,7 +313,7 @@ registerAction2(class extends NotebookCellAction { } }); -registerAction2(class extends NotebookCellAction { +registerAction2(class StopExecuteCell extends NotebookCellAction { constructor() { super({ id: CANCEL_CELL_COMMAND_ID, @@ -442,10 +443,11 @@ export class DeleteCellAction extends MenuItemAction { } } -registerAction2(class extends NotebookCellAction { +registerAction2(class ExecuteCellSelectBelow extends NotebookCellAction { constructor() { super({ id: EXECUTE_CELL_SELECT_BELOW, + precondition: ContextKeyExpr.greater(NOTEBOOK_KERNEL_COUNT.key, 0), title: localize('notebookActions.executeAndSelectBelow', "Execute Notebook Cell and Select Below"), keybinding: { when: NOTEBOOK_CELL_LIST_FOCUSED, @@ -478,10 +480,11 @@ registerAction2(class extends NotebookCellAction { } }); -registerAction2(class extends NotebookCellAction { +registerAction2(class ExecuteCellInsertBelow extends NotebookCellAction { constructor() { super({ id: EXECUTE_CELL_INSERT_BELOW, + precondition: ContextKeyExpr.greater(NOTEBOOK_KERNEL_COUNT.key, 0), title: localize('notebookActions.executeAndInsertBelow', "Execute Notebook Cell and Insert Below"), keybinding: { when: NOTEBOOK_CELL_LIST_FOCUSED, From d9c653c8b68449695e27d82967eeec4f71ea4d7e Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 15 Feb 2021 17:17:04 +0100 Subject: [PATCH 168/325] increase default timeout for event waiting, fixes https://github.com/microsoft/vscode/issues/116704 --- extensions/vscode-api-tests/src/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/vscode-api-tests/src/utils.ts b/extensions/vscode-api-tests/src/utils.ts index 4bddd45a5e3..8d94c8ea120 100644 --- a/extensions/vscode-api-tests/src/utils.ts +++ b/extensions/vscode-api-tests/src/utils.ts @@ -122,7 +122,7 @@ export function assertNoRpcFromEntry(entry: [obj: any, name: string]) { assert.strictEqual(proxyPaths.length, 0, proxyPaths.join('\n')); // happens... } -export async function asPromise(event: vscode.Event, timeout = 1000): Promise { +export async function asPromise(event: vscode.Event, timeout = 5000): Promise { return new Promise((resolve, reject) => { const handle = setTimeout(() => { From e4e0919c0ec20264fe69e40025f62d4140928df4 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 15 Feb 2021 17:30:58 +0100 Subject: [PATCH 169/325] refine precondition so that markdown cells always "execute" --- .../contrib/notebook/browser/contrib/coreActions.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts index 6e8611e59ec..26772735238 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts @@ -232,7 +232,7 @@ registerAction2(class ExecuteCell extends NotebookCellAction { constructor() { super({ id: EXECUTE_CELL_COMMAND_ID, - precondition: ContextKeyExpr.greater(NOTEBOOK_KERNEL_COUNT.key, 0), + precondition: ContextKeyExpr.or(ContextKeyExpr.greater(NOTEBOOK_KERNEL_COUNT.key, 0), NOTEBOOK_CELL_TYPE.isEqualTo('markdown')), title: localize('notebookActions.execute', "Execute Cell"), keybinding: { when: NOTEBOOK_CELL_LIST_FOCUSED, @@ -447,7 +447,7 @@ registerAction2(class ExecuteCellSelectBelow extends NotebookCellAction { constructor() { super({ id: EXECUTE_CELL_SELECT_BELOW, - precondition: ContextKeyExpr.greater(NOTEBOOK_KERNEL_COUNT.key, 0), + precondition: ContextKeyExpr.or(ContextKeyExpr.greater(NOTEBOOK_KERNEL_COUNT.key, 0), NOTEBOOK_CELL_TYPE.isEqualTo('markdown')), title: localize('notebookActions.executeAndSelectBelow', "Execute Notebook Cell and Select Below"), keybinding: { when: NOTEBOOK_CELL_LIST_FOCUSED, @@ -484,7 +484,7 @@ registerAction2(class ExecuteCellInsertBelow extends NotebookCellAction { constructor() { super({ id: EXECUTE_CELL_INSERT_BELOW, - precondition: ContextKeyExpr.greater(NOTEBOOK_KERNEL_COUNT.key, 0), + precondition: ContextKeyExpr.or(ContextKeyExpr.greater(NOTEBOOK_KERNEL_COUNT.key, 0), NOTEBOOK_CELL_TYPE.isEqualTo('markdown')), title: localize('notebookActions.executeAndInsertBelow', "Execute Notebook Cell and Insert Below"), keybinding: { when: NOTEBOOK_CELL_LIST_FOCUSED, From 6c12d9f2c4aa9f14ce1ca81033ebf31ea48c0bc0 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 15 Feb 2021 17:54:05 +0100 Subject: [PATCH 170/325] storage - add first cut lifecycle controlled from main side --- src/vs/platform/storage/common/storageIpc.ts | 18 +++---- .../storage/electron-main/storageIpc.ts | 10 ---- .../storage/electron-main/storageMain.ts | 39 +++++++++------ .../electron-main/storageMainService.ts | 8 ++- .../electron-sandbox/storageService2.ts | 2 +- .../electron-main/storageMainService.test.ts | 50 +++++++++++++++++-- 6 files changed, 86 insertions(+), 41 deletions(-) diff --git a/src/vs/platform/storage/common/storageIpc.ts b/src/vs/platform/storage/common/storageIpc.ts index 5669ec1f22f..fe88c0815c7 100644 --- a/src/vs/platform/storage/common/storageIpc.ts +++ b/src/vs/platform/storage/common/storageIpc.ts @@ -57,9 +57,14 @@ abstract class BaseStorageDatabaseClient extends Disposable implements IStorageD } async close(): Promise { - const serializableRequest: IBaseSerializableStorageRequest = { workspace: this.workspace }; - return this.channel.call('close', serializableRequest); + // The database connection is not owned by us, but rather on the + // main side, as such we do not forward the close() request but + // let main side handle this properly via lifecycle methods. + // + // However, we cleanup our listeners because we are no longer + // interested in change events from the global database + this.dispose(); } } @@ -86,15 +91,6 @@ class GlobalStorageDatabaseClient extends BaseStorageDatabaseClient implements I }); } } - - close(): Promise { - - // Remove our listeners on `close` because we are no longer - // interested in change events from the global database - this.dispose(); - - return super.close(); - } } class WorkspaceStorageDatabaseClient extends BaseStorageDatabaseClient implements IStorageDatabase { diff --git a/src/vs/platform/storage/electron-main/storageIpc.ts b/src/vs/platform/storage/electron-main/storageIpc.ts index 27084af2ee6..2fb542e34cf 100644 --- a/src/vs/platform/storage/electron-main/storageIpc.ts +++ b/src/vs/platform/storage/electron-main/storageIpc.ts @@ -104,16 +104,6 @@ export class StorageDatabaseChannel extends Disposable implements IServerChannel break; } - case 'close': { - if (workspace) { - // Only allow to close workspace storage databases but not - // the global database that is shared across multiple connections - return storage.close(); - } - - break; - } - default: throw new Error(`Call not found: ${command}`); } diff --git a/src/vs/platform/storage/electron-main/storageMain.ts b/src/vs/platform/storage/electron-main/storageMain.ts index eb462d73cd1..e0d15b548e3 100644 --- a/src/vs/platform/storage/electron-main/storageMain.ts +++ b/src/vs/platform/storage/electron-main/storageMain.ts @@ -16,7 +16,7 @@ import { IS_NEW_KEY } from 'vs/platform/storage/common/storage'; import { currentSessionDateStorageKey, firstSessionDateStorageKey, instanceStorageKey, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry'; import { generateUuid } from 'vs/base/common/uuid'; import { IEmptyWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; +import { ILifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; /** * Provides access to global and workspace storage from the @@ -114,8 +114,26 @@ abstract class BaseStorageMain extends Disposable implements IStorageMain { private initializePromise: Promise | undefined = undefined; - constructor(protected readonly logService: ILogService) { + constructor( + protected readonly logService: ILogService, + private readonly lifecycleMainService: ILifecycleMainService + ) { super(); + + this.registerListeners(); + } + + private registerListeners(): void { + + // Lifecycle: Warmup (in parallel to window open) + (async () => { + await this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen); + + this.initialize(); + })(); + + // Lifecycle: Shutdown + this.lifecycleMainService.onWillShutdown(e => e.join(this.close())); } initialize(): Promise { @@ -199,17 +217,9 @@ export class GlobalStorageMain extends BaseStorageMain implements IStorageMain { constructor( logService: ILogService, private readonly environmentService: IEnvironmentService, - private readonly lifecycleMainService: ILifecycleMainService + lifecycleMainService: ILifecycleMainService ) { - super(logService); - - this.registerListeners(); - } - - private registerListeners(): void { - - // Lifecycle - this.lifecycleMainService.onWillShutdown(e => e.join(this.close())); + super(logService, lifecycleMainService); } protected async doInitialize(): Promise { @@ -278,9 +288,10 @@ export class WorkspaceStorageMain extends BaseStorageMain implements IStorageMai constructor( private workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier, logService: ILogService, - private readonly environmentService: IEnvironmentService + private readonly environmentService: IEnvironmentService, + lifecycleMainService: ILifecycleMainService ) { - super(logService); + super(logService, lifecycleMainService); } protected async doInitialize(): Promise { diff --git a/src/vs/platform/storage/electron-main/storageMainService.ts b/src/vs/platform/storage/electron-main/storageMainService.ts index 832943ebb04..f9b408032b9 100644 --- a/src/vs/platform/storage/electron-main/storageMainService.ts +++ b/src/vs/platform/storage/electron-main/storageMainService.ts @@ -48,8 +48,14 @@ export class StorageMainService implements IStorageMainService { return this.globalStorage; // only once } + this.logService.trace(`StorageMainService: creating global storage`); + const globalStorage = new GlobalStorageMain(this.logService, this.environmentService, this.lifecycleMainService); + once(globalStorage.onDidCloseStorage)(() => { + this.logService.trace(`StorageMainService: closed global storage`); + }); + return globalStorage; } @@ -61,7 +67,7 @@ export class StorageMainService implements IStorageMainService { private readonly mapWorkspaceToStorage = new Map(); private createWorkspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier): IStorageMain { - const workspaceStorage = new WorkspaceStorageMain(workspace, this.logService, this.environmentService); + const workspaceStorage = new WorkspaceStorageMain(workspace, this.logService, this.environmentService, this.lifecycleMainService); return workspaceStorage; } diff --git a/src/vs/platform/storage/electron-sandbox/storageService2.ts b/src/vs/platform/storage/electron-sandbox/storageService2.ts index b2dd29e21f2..e5415b5b907 100644 --- a/src/vs/platform/storage/electron-sandbox/storageService2.ts +++ b/src/vs/platform/storage/electron-sandbox/storageService2.ts @@ -146,7 +146,7 @@ export class NativeStorageService2 extends AbstractStorageService { this.globalStorage.items, this.workspaceStorage ? this.workspaceStorage.items : new Map(), this.environmentService.globalStorageHome.fsPath, - this.workspace ? joinPath(this.environmentService.workspaceStorageHome, this.workspace.id, 'state.vscdb').fsPath : '' + this.workspace ? `${joinPath(this.environmentService.workspaceStorageHome, this.workspace.id, 'state.vscdb').fsPath} [!!! Experimental Main Storage !!!]` : '' ); } diff --git a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts index ae3f8165583..cdde6a0aa04 100644 --- a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts +++ b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts @@ -5,7 +5,7 @@ import { promises } from 'fs'; import { tmpdir } from 'os'; -import { strictEqual } from 'assert'; +import { notStrictEqual, strictEqual } from 'assert'; import { URI } from 'vs/base/common/uri'; import { rimraf } from 'vs/base/node/pfs'; import { flakySuite, getRandomTestPath } from 'vs/base/test/node/testUtils'; @@ -18,10 +18,11 @@ import { IStorageChangeEvent, IStorageMain } from 'vs/platform/storage/electron- import { generateUuid } from 'vs/base/common/uuid'; import { IS_NEW_KEY } from 'vs/platform/storage/common/storage'; import { joinPath } from 'vs/base/common/resources'; -import { ILifecycleMainService, LifecycleMainPhase, UnloadReason } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; -import { Event } from 'vs/base/common/event'; +import { ILifecycleMainService, LifecycleMainPhase, ShutdownEvent, UnloadReason } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; +import { Emitter, Event } from 'vs/base/common/event'; import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; import { ICodeWindow } from 'vs/platform/windows/electron-main/windows'; +import { Promises } from 'vs/base/common/async'; flakySuite('StorageMainService (native)', function () { @@ -49,7 +50,24 @@ flakySuite('StorageMainService (native)', function () { _serviceBrand: undefined; onBeforeShutdown = Event.None; - onWillShutdown = Event.None; + + private readonly _onWillShutdown = new Emitter(); + readonly onWillShutdown = this._onWillShutdown.event; + + async fireOnWillShutdown(): Promise { + const joiners: Promise[] = []; + + this._onWillShutdown.fire({ + join(promise) { + if (promise) { + joiners.push(promise); + } + } + }); + + await Promises.settled(joiners); + } + onBeforeWindowClose = Event.None; onBeforeWindowUnload = Event.None; @@ -166,4 +184,28 @@ flakySuite('StorageMainService (native)', function () { return storageMainService.workspaceStorage(workspace); }, false); }); + + test('storage closed onWillShutdown', async function () { + const lifecycleMainService = new StorageTestLifecycleMainService(); + const workspace = { id: generateUuid() }; + const storageMainService = new StorageMainService(new NullLogService(), environmentService, lifecycleMainService); + + let storage = storageMainService.workspaceStorage(workspace); + let didCloseStorage = false; + storage.onDidCloseStorage(() => { + didCloseStorage = true; + }); + + strictEqual(storage, storageMainService.workspaceStorage(workspace)); // same instance as long as not closed + + await storage.initialize(); + + await lifecycleMainService.fireOnWillShutdown(); + strictEqual(didCloseStorage, true); + + let storage2 = storageMainService.workspaceStorage(workspace); + notStrictEqual(storage, storage2); + + return storage2.close(); + }); }); From 8263f1c66a364d513b6a4a5779c4e1f76fb1fd5a Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 15 Feb 2021 18:35:41 +0100 Subject: [PATCH 171/325] actionBar: do not eat up the arrow key if there is only one item in the action bar --- src/vs/base/browser/ui/actionbar/actionbar.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index 3f5402971bc..808b9dcdcee 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -147,9 +147,9 @@ export class ActionBar extends Disposable implements IActionRunner { const focusedItem = typeof this.focusedItem === 'number' ? this.viewItems[this.focusedItem] : undefined; if (previousKeys && (event.equals(previousKeys[0]) || event.equals(previousKeys[1]))) { - eventHandled = this.focusPrevious(); + eventHandled = this.focusPrevious() && this.viewItems.length > 1; } else if (nextKeys && (event.equals(nextKeys[0]) || event.equals(nextKeys[1]))) { - eventHandled = this.focusNext(); + eventHandled = this.focusNext() && this.viewItems.length > 1; } else if (event.equals(KeyCode.Escape) && this.cancelHasListener) { this._onDidCancel.fire(); } else if (event.equals(KeyCode.Tab) && focusedItem instanceof BaseActionViewItem && focusedItem.trapsArrowNavigation) { From 5f5ceba51a31fc58eee54f0f59adff7efae5a8e7 Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 15 Feb 2021 20:29:33 +0100 Subject: [PATCH 172/325] actionBar: allow to focus disabled items --- .../browser/ui/actionbar/actionViewItems.ts | 11 +------ src/vs/base/browser/ui/actionbar/actionbar.ts | 31 +++++-------------- src/vs/base/browser/ui/checkbox/checkbox.ts | 4 --- .../ui/dropdown/dropdownActionViewItem.ts | 1 - 4 files changed, 8 insertions(+), 39 deletions(-) diff --git a/src/vs/base/browser/ui/actionbar/actionViewItems.ts b/src/vs/base/browser/ui/actionbar/actionViewItems.ts index 582761b27e1..9abeda1c547 100644 --- a/src/vs/base/browser/ui/actionbar/actionViewItems.ts +++ b/src/vs/base/browser/ui/actionbar/actionViewItems.ts @@ -14,7 +14,7 @@ import { EventType as TouchEventType, Gesture } from 'vs/base/browser/touch'; import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; import { DataTransfers } from 'vs/base/browser/dnd'; import { isFirefox } from 'vs/base/browser/browser'; -import { $, addDisposableListener, append, EventHelper, EventLike, EventType, removeTabIndexAndUpdateFocus } from 'vs/base/browser/dom'; +import { $, addDisposableListener, append, EventHelper, EventLike, EventType } from 'vs/base/browser/dom'; export interface IBaseActionViewItemOptions { draggable?: boolean; @@ -181,10 +181,6 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem { } } - get isFocusable(): boolean { - return this.element?.tabIndex === 0; - } - setFocusable(focusable: boolean): void { if (this.element) { this.element.tabIndex = focusable ? 0 : -1; @@ -292,10 +288,6 @@ export class ActionViewItem extends BaseActionViewItem { } } - get isFocusable(): boolean { - return this.label?.tabIndex === 0; - } - setFocusable(focusable: boolean): void { if (this.label) { this.label.tabIndex = focusable ? 0 : -1; @@ -364,7 +356,6 @@ export class ActionViewItem extends BaseActionViewItem { if (this.label) { this.label.setAttribute('aria-disabled', 'true'); this.label.classList.add('disabled'); - removeTabIndexAndUpdateFocus(this.label); } if (this.element) { diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index 808b9dcdcee..8a912e1255c 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./actionbar'; -import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; -import { IAction, IActionRunner, ActionRunner, IRunEvent, Separator, IActionViewItem, IActionViewItemProvider, Action } from 'vs/base/common/actions'; +import { Disposable, dispose } from 'vs/base/common/lifecycle'; +import { IAction, IActionRunner, ActionRunner, IRunEvent, Separator, IActionViewItem, IActionViewItemProvider } from 'vs/base/common/actions'; import * as DOM from 'vs/base/browser/dom'; import * as types from 'vs/base/common/types'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; @@ -82,8 +82,6 @@ export class ActionBar extends Disposable implements IActionRunner { private _onBeforeRun = this._register(new Emitter()); readonly onBeforeRun = this._onBeforeRun.event; - private actionChangeListeners: IDisposable[] = []; - constructor(container: HTMLElement, options: IActionBarOptions = {}) { super(); @@ -225,13 +223,13 @@ export class ActionBar extends Disposable implements IActionRunner { // Some action bars should not be focusable at times // When an action bar is not focusable make sure to make all the elements inside it not focusable - // When an action bar is focusable again, make sure the first enabled item can be focused + // When an action bar is focusable again, make sure the first item can be focused setFocusable(focusable: boolean): void { this.focusable = focusable; if (this.focusable) { - const firstEnabled = this.viewItems.find(vi => vi instanceof BaseActionViewItem && vi.isEnabled()); - if (firstEnabled instanceof BaseActionViewItem) { - firstEnabled.setFocusable(true); + const first = this.viewItems.find(vi => vi instanceof BaseActionViewItem); + if (first instanceof BaseActionViewItem) { + first.setFocusable(true); } } else { this.viewItems.forEach(vi => { @@ -320,18 +318,7 @@ export class ActionBar extends Disposable implements IActionRunner { item.setActionContext(this.context); item.render(actionViewItemElement); - this.actionChangeListeners.push(action instanceof Action ? action.onDidChange(e => { - // In case an action got disabled and it was last focused in the action bar - // We need to reset the tabIndex to be set on the first enabled item - if (e.enabled === false && item instanceof BaseActionViewItem && item.isFocusable) { - const firstEnabled = this.viewItems.find(vi => vi instanceof BaseActionViewItem && vi.isEnabled()); - if (firstEnabled instanceof BaseActionViewItem) { - firstEnabled.setFocusable(true); - } - } - }) : Disposable.None); - - if (this.focusable && this.viewItems.every(i => !i.isEnabled()) && item instanceof BaseActionViewItem && item.isEnabled()) { + if (this.focusable && this.viewItems.length === 0 && item instanceof BaseActionViewItem) { // We need to allow for the first enabled item to be focused on using tab navigation #106441 item.setFocusable(true); } @@ -379,15 +366,12 @@ export class ActionBar extends Disposable implements IActionRunner { if (index >= 0 && index < this.viewItems.length) { this.actionsList.removeChild(this.actionsList.childNodes[index]); dispose(this.viewItems.splice(index, 1)); - dispose(this.actionChangeListeners.splice(index, 1)); this._actionIds.splice(index, 1); } } clear(): void { dispose(this.viewItems); - dispose(this.actionChangeListeners); - this.actionChangeListeners = []; this.viewItems = []; this._actionIds = []; DOM.clearNode(this.actionsList); @@ -529,7 +513,6 @@ export class ActionBar extends Disposable implements IActionRunner { dispose(): void { dispose(this.viewItems); - dispose(this.actionChangeListeners); this.viewItems = []; this._actionIds = []; diff --git a/src/vs/base/browser/ui/checkbox/checkbox.ts b/src/vs/base/browser/ui/checkbox/checkbox.ts index 037ddbba862..485d85d16d4 100644 --- a/src/vs/base/browser/ui/checkbox/checkbox.ts +++ b/src/vs/base/browser/ui/checkbox/checkbox.ts @@ -90,10 +90,6 @@ export class CheckboxActionViewItem extends BaseActionViewItem { } } - get isFocusable(): boolean { - return this.checkbox?.domNode.tabIndex === 0; - } - setFocusable(focusable: boolean): void { if (this.checkbox) { this.checkbox.domNode.tabIndex = focusable ? 0 : -1; diff --git a/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts b/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts index 353b766ef1d..2aaac8a7ab3 100644 --- a/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts +++ b/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts @@ -179,5 +179,4 @@ export class ActionWithDropdownActionViewItem extends ActionViewItem { this.dropdownMenuActionViewItem.render(this.element); } } - } From 3479bb35904eb046c0974090794cac9c76173796 Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 15 Feb 2021 20:30:20 +0100 Subject: [PATCH 173/325] button checkbox and menu: do not automatically remove tabIndex from disabled items --- src/vs/base/browser/ui/button/button.ts | 3 +-- src/vs/base/browser/ui/checkbox/checkbox.ts | 2 -- src/vs/base/browser/ui/menu/menu.ts | 7 +++++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/base/browser/ui/button/button.ts b/src/vs/base/browser/ui/button/button.ts index ebfe8d59f17..473eb2a2ec4 100644 --- a/src/vs/base/browser/ui/button/button.ts +++ b/src/vs/base/browser/ui/button/button.ts @@ -12,7 +12,7 @@ import { Event as BaseEvent, Emitter } from 'vs/base/common/event'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { Gesture, EventType as TouchEventType } from 'vs/base/browser/touch'; import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; -import { addDisposableListener, IFocusTracker, EventType, EventHelper, trackFocus, reset, removeTabIndexAndUpdateFocus } from 'vs/base/browser/dom'; +import { addDisposableListener, IFocusTracker, EventType, EventHelper, trackFocus, reset } from 'vs/base/browser/dom'; import { IContextMenuProvider } from 'vs/base/browser/contextmenu'; import { Action, IAction, IActionRunner } from 'vs/base/common/actions'; import { CSSIcon, Codicon } from 'vs/base/common/codicons'; @@ -214,7 +214,6 @@ export class Button extends Disposable implements IButton { } else { this._element.classList.add('disabled'); this._element.setAttribute('aria-disabled', String(true)); - removeTabIndexAndUpdateFocus(this._element); } } diff --git a/src/vs/base/browser/ui/checkbox/checkbox.ts b/src/vs/base/browser/ui/checkbox/checkbox.ts index 485d85d16d4..d9319424fc5 100644 --- a/src/vs/base/browser/ui/checkbox/checkbox.ts +++ b/src/vs/base/browser/ui/checkbox/checkbox.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./checkbox'; -import * as DOM from 'vs/base/browser/dom'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { Widget } from 'vs/base/browser/ui/widget'; import { Color } from 'vs/base/common/color'; @@ -215,7 +214,6 @@ export class Checkbox extends Widget { } disable(): void { - DOM.removeTabIndexAndUpdateFocus(this.domNode); this.domNode.setAttribute('aria-disabled', String(true)); } } diff --git a/src/vs/base/browser/ui/menu/menu.ts b/src/vs/base/browser/ui/menu/menu.ts index b94c9c99ac2..9a9132359ce 100644 --- a/src/vs/base/browser/ui/menu/menu.ts +++ b/src/vs/base/browser/ui/menu/menu.ts @@ -8,7 +8,7 @@ import * as strings from 'vs/base/common/strings'; import { IActionRunner, IAction, SubmenuAction, Separator, IActionViewItemProvider, EmptySubmenuAction } from 'vs/base/common/actions'; import { ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; import { ResolvedKeybinding, KeyCode } from 'vs/base/common/keyCodes'; -import { EventType, EventHelper, EventLike, removeTabIndexAndUpdateFocus, isAncestor, addDisposableListener, append, $, clearNode, createStyleSheet, isInShadowDOM, getActiveElement, Dimension, IDomNodePagePosition } from 'vs/base/browser/dom'; +import { EventType, EventHelper, EventLike, isAncestor, addDisposableListener, append, $, clearNode, createStyleSheet, isInShadowDOM, getActiveElement, Dimension, IDomNodePagePosition } from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { RunOnceScheduler } from 'vs/base/common/async'; import { DisposableStore } from 'vs/base/common/lifecycle'; @@ -618,20 +618,23 @@ class BaseMenuActionViewItem extends BaseActionViewItem { if (this.getAction().enabled) { if (this.element) { this.element.classList.remove('disabled'); + this.element.removeAttribute('aria-disabled'); } if (this.item) { this.item.classList.remove('disabled'); + this.item.removeAttribute('aria-disabled'); this.item.tabIndex = 0; } } else { if (this.element) { this.element.classList.add('disabled'); + this.element.setAttribute('aria-disabled', 'true'); } if (this.item) { this.item.classList.add('disabled'); - removeTabIndexAndUpdateFocus(this.item); + this.item.setAttribute('aria-disabled', 'true'); } } } From bf0e8299db7994d0f33617c0c8c51df8b10c649e Mon Sep 17 00:00:00 2001 From: Utku Gultopu Date: Mon, 15 Feb 2021 16:24:05 -0500 Subject: [PATCH 174/325] Fix misspelling of "likelihood" --- src/vs/platform/files/common/fileService.ts | 2 +- .../contrib/performance/browser/perfviewEditor.ts | 2 +- src/vs/workbench/services/timer/browser/timerService.ts | 8 ++++---- .../services/timer/electron-sandbox/timerService.ts | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/vs/platform/files/common/fileService.ts b/src/vs/platform/files/common/fileService.ts index ab2a5236895..3dfc15e444a 100644 --- a/src/vs/platform/files/common/fileService.ts +++ b/src/vs/platform/files/common/fileService.ts @@ -458,7 +458,7 @@ export class FileService extends Disposable implements IFileService { try { // if the etag is provided, we await the result of the validation - // due to the likelyhood of hitting a NOT_MODIFIED_SINCE result. + // due to the likelihood of hitting a NOT_MODIFIED_SINCE result. // otherwise, we let it run in parallel to the file reading for // optimal startup performance. if (options && typeof options.etag === 'string' && options.etag !== ETAG_DISABLED) { diff --git a/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts b/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts index 51d3d495873..7e65342f581 100644 --- a/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts +++ b/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts @@ -156,7 +156,7 @@ class PerfModelContentProvider implements ITextModelContentProvider { if (metrics.meminfo) { md.li(`Memory(Process): ${(metrics.meminfo.workingSetSize / ByteSize.KB).toFixed(2)} MB working set(${(metrics.meminfo.privateBytes / ByteSize.KB).toFixed(2)}MB private, ${(metrics.meminfo.sharedBytes / ByteSize.KB).toFixed(2)}MB shared)`); } - md.li(`VM(likelyhood): ${metrics.isVMLikelyhood}%`); + md.li(`VM(likelihood): ${metrics.isVMLikelihood}%`); md.li(`Initial Startup: ${metrics.initialStartup}`); md.li(`Has ${metrics.windowCount - 1} other windows`); md.li(`Screen Reader Active: ${metrics.hasAccessibilitySupport}`); diff --git a/src/vs/workbench/services/timer/browser/timerService.ts b/src/vs/workbench/services/timer/browser/timerService.ts index 324de644b65..fbf80f6aad0 100644 --- a/src/vs/workbench/services/timer/browser/timerService.ts +++ b/src/vs/workbench/services/timer/browser/timerService.ts @@ -68,7 +68,7 @@ export interface IMemoryInfo { "cpus.model" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, "initialStartup" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "hasAccessibilitySupport" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "isVMLikelyhood" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, + "isVMLikelihood" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "emptyWorkbench" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "loadavg" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } } @@ -324,7 +324,7 @@ export interface IStartupMetrics { }; readonly hasAccessibilitySupport: boolean; - readonly isVMLikelyhood?: number; + readonly isVMLikelihood?: number; readonly platform?: string; readonly release?: string; readonly arch?: string; @@ -546,7 +546,7 @@ export abstract class AbstractTimerService implements ITimerService { meminfo: undefined, cpus: undefined, loadavg: undefined, - isVMLikelyhood: undefined, + isVMLikelihood: undefined, initialStartup, hasAccessibilitySupport: this._accessibilityService.isScreenReaderOptimized(), emptyWorkbench: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY @@ -578,7 +578,7 @@ export class TimerService extends AbstractTimerService { return 1; } protected async _extendStartupInfo(info: Writeable): Promise { - info.isVMLikelyhood = 0; + info.isVMLikelihood = 0; info.platform = navigator.userAgent; info.release = navigator.appVersion; } diff --git a/src/vs/workbench/services/timer/electron-sandbox/timerService.ts b/src/vs/workbench/services/timer/electron-sandbox/timerService.ts index cfd5a044410..feb1c404ae2 100644 --- a/src/vs/workbench/services/timer/electron-sandbox/timerService.ts +++ b/src/vs/workbench/services/timer/electron-sandbox/timerService.ts @@ -68,7 +68,7 @@ export class TimerService extends AbstractTimerService { sharedBytes: processMemoryInfo.shared }; - info.isVMLikelyhood = Math.round((virtualMachineHint * 100)); + info.isVMLikelihood = Math.round((virtualMachineHint * 100)); const rawCpus = osProperties.cpus; if (rawCpus && rawCpus.length > 0) { From 2b1ab52273b8d02b831b2b040fc203a85baa2810 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 16 Feb 2021 07:40:36 +0100 Subject: [PATCH 175/325] storage - remove unused onWillSaveState event (main) --- .../storage/electron-main/storageMain.ts | 23 ------------------- .../electron-sandbox/storageService2.ts | 1 + 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/src/vs/platform/storage/electron-main/storageMain.ts b/src/vs/platform/storage/electron-main/storageMain.ts index e0d15b548e3..9bb316f0ef3 100644 --- a/src/vs/platform/storage/electron-main/storageMain.ts +++ b/src/vs/platform/storage/electron-main/storageMain.ts @@ -29,17 +29,6 @@ export interface IStorageMain { */ readonly onDidChangeStorage: Event; - /** - * Emitted when the storage is about to persist. This is the right time - * to persist data to ensure it is stored before the application shuts - * down. - * - * Note: this event may be fired many times, not only on shutdown to prevent - * loss of state in situations where the shutdown is not sufficient to - * persist the data properly. - */ - readonly onWillSaveState: Event; - /** * Emitted when the storage is closed. */ @@ -104,9 +93,6 @@ abstract class BaseStorageMain extends Disposable implements IStorageMain { protected readonly _onDidChangeStorage = this._register(new Emitter()); readonly onDidChangeStorage = this._onDidChangeStorage.event; - protected readonly _onWillSaveState = this._register(new Emitter()); - readonly onWillSaveState = this._onWillSaveState.event; - private readonly _onDidCloseStorage = this._register(new Emitter()); readonly onDidCloseStorage = this._onDidCloseStorage.event; @@ -269,15 +255,6 @@ export class GlobalStorageMain extends BaseStorageMain implements IStorageMain { storage.set(lastSessionDateStorageKey, typeof lastSessionDate === 'undefined' ? null : lastSessionDate); storage.set(currentSessionDateStorageKey, currentSessionDate); } - - close(): Promise { - - // Signal as event so that clients can still store data - this._onWillSaveState.fire(); - - // Do it - return super.close(); - } } export class WorkspaceStorageMain extends BaseStorageMain implements IStorageMain { diff --git a/src/vs/platform/storage/electron-sandbox/storageService2.ts b/src/vs/platform/storage/electron-sandbox/storageService2.ts index e5415b5b907..8d7c315bd6c 100644 --- a/src/vs/platform/storage/electron-sandbox/storageService2.ts +++ b/src/vs/platform/storage/electron-sandbox/storageService2.ts @@ -32,6 +32,7 @@ export class NativeStorageService2 extends AbstractStorageService { ) { super(); + // Connect to storage via channel client const storageDataBaseClient = new StorageDatabaseChannelClient(mainProcessService.getChannel('storage'), workspace); this.globalStorage = new Storage(storageDataBaseClient.globalStorage); this.workspaceStorage = storageDataBaseClient.workspaceStorage ? new Storage(storageDataBaseClient.workspaceStorage) : undefined; From 3bb3da8281d5acfae47b6e7a3cb13ef67bb79ec1 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 16 Feb 2021 08:05:38 +0100 Subject: [PATCH 176/325] storage - move more things into abstract storage service --- .../storage/browser/storageService.ts | 49 +----- src/vs/platform/storage/common/storage.ts | 144 +++++++----------- .../electron-sandbox/storageService2.ts | 49 +----- .../platform/storage/node/storageService.ts | 55 +------ 4 files changed, 70 insertions(+), 227 deletions(-) diff --git a/src/vs/platform/storage/browser/storageService.ts b/src/vs/platform/storage/browser/storageService.ts index 0776161e830..aa2eb5f6c7d 100644 --- a/src/vs/platform/storage/browser/storageService.ts +++ b/src/vs/platform/storage/browser/storageService.ts @@ -5,7 +5,7 @@ import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Emitter } from 'vs/base/common/event'; -import { StorageScope, logStorage, IS_NEW_KEY, AbstractStorageService } from 'vs/platform/storage/common/storage'; +import { StorageScope, IS_NEW_KEY, AbstractStorageService } from 'vs/platform/storage/common/storage'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces'; import { IFileService, FileChangeType } from 'vs/platform/files/common/files'; @@ -14,7 +14,6 @@ import { URI } from 'vs/base/common/uri'; import { joinPath } from 'vs/base/common/resources'; import { runWhenIdle, RunOnceScheduler, Promises } from 'vs/base/common/async'; import { VSBuffer } from 'vs/base/common/buffer'; -import { assertIsDefined } from 'vs/base/common/types'; export class BrowserStorageService extends AbstractStorageService { @@ -100,56 +99,18 @@ export class BrowserStorageService extends AbstractStorageService { this.periodicFlushScheduler.schedule(); } - get(key: string, scope: StorageScope, fallbackValue: string): string; - get(key: string, scope: StorageScope): string | undefined; - get(key: string, scope: StorageScope, fallbackValue?: string): string | undefined { - return this.getStorage(scope).get(key, fallbackValue); + protected getStorage(scope: StorageScope): IStorage | undefined { + return scope === StorageScope.GLOBAL ? this.globalStorage : this.workspaceStorage; } - getBoolean(key: string, scope: StorageScope, fallbackValue: boolean): boolean; - getBoolean(key: string, scope: StorageScope): boolean | undefined; - getBoolean(key: string, scope: StorageScope, fallbackValue?: boolean): boolean | undefined { - return this.getStorage(scope).getBoolean(key, fallbackValue); - } - - getNumber(key: string, scope: StorageScope, fallbackValue: number): number; - getNumber(key: string, scope: StorageScope): number | undefined; - getNumber(key: string, scope: StorageScope, fallbackValue?: number): number | undefined { - return this.getStorage(scope).getNumber(key, fallbackValue); - } - - protected doStore(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): void { - this.getStorage(scope).set(key, value); - } - - protected doRemove(key: string, scope: StorageScope): void { - this.getStorage(scope).delete(key); - } - - private getStorage(scope: StorageScope): IStorage { - return assertIsDefined(scope === StorageScope.GLOBAL ? this.globalStorage : this.workspaceStorage); - } - - async logStorage(): Promise { - return logStorage( - assertIsDefined(this.globalStorage).items, - assertIsDefined(this.workspaceStorage).items, - assertIsDefined(this.globalStorageFile).toString(), - assertIsDefined(this.workspaceStorageFile).toString() - ); + protected getLogDetails(scope: StorageScope): string | undefined { + return scope === StorageScope.GLOBAL ? this.globalStorageFile?.toString() : this.workspaceStorageFile?.toString(); } async migrate(toWorkspace: IWorkspaceInitializationPayload): Promise { throw new Error('Migrating storage is currently unsupported in Web'); } - protected async doFlush(): Promise { - await Promises.settled([ - this.getStorage(StorageScope.GLOBAL).whenFlushed(), - this.getStorage(StorageScope.WORKSPACE).whenFlushed() - ]); - } - private doFlushWhenIdle(): void { // Dispose any previous idle runner diff --git a/src/vs/platform/storage/common/storage.ts b/src/vs/platform/storage/common/storage.ts index 3d176f5b6d8..aad6f035908 100644 --- a/src/vs/platform/storage/common/storage.ts +++ b/src/vs/platform/storage/common/storage.ts @@ -8,6 +8,8 @@ import { Event, Emitter, PauseableEmitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { isUndefinedOrNull } from 'vs/base/common/types'; import { IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces'; +import { InMemoryStorageDatabase, IStorage, Storage } from 'vs/base/parts/storage/common/storage'; +import { Promises } from 'vs/base/common/async'; export const IS_NEW_KEY = '__$__isNewStorageMarker'; const TARGET_KEY = '__$__targetStorageMarker'; @@ -257,6 +259,24 @@ export abstract class AbstractStorageService extends Disposable implements IStor this._onWillSaveState.fire({ reason }); } + get(key: string, scope: StorageScope, fallbackValue: string): string; + get(key: string, scope: StorageScope): string | undefined; + get(key: string, scope: StorageScope, fallbackValue?: string): string | undefined { + return this.getStorage(scope)?.get(key, fallbackValue); + } + + getBoolean(key: string, scope: StorageScope, fallbackValue: boolean): boolean; + getBoolean(key: string, scope: StorageScope): boolean | undefined; + getBoolean(key: string, scope: StorageScope, fallbackValue?: boolean): boolean | undefined { + return this.getStorage(scope)?.getBoolean(key, fallbackValue); + } + + getNumber(key: string, scope: StorageScope, fallbackValue: number): number; + getNumber(key: string, scope: StorageScope): number | undefined; + getNumber(key: string, scope: StorageScope, fallbackValue?: number): number | undefined { + return this.getStorage(scope)?.getNumber(key, fallbackValue); + } + store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope, target: StorageTarget): void { // We remove the key for undefined/null values @@ -272,7 +292,7 @@ export abstract class AbstractStorageService extends Disposable implements IStor this.updateKeyTarget(key, scope, target); // Store actual value - this.doStore(key, value, scope); + this.getStorage(scope)?.set(key, value); }); } @@ -285,7 +305,7 @@ export abstract class AbstractStorageService extends Disposable implements IStor this.updateKeyTarget(key, scope, undefined); // Remove actual key - this.doRemove(key, scope); + this.getStorage(scope)?.delete(key); }); } @@ -326,7 +346,7 @@ export abstract class AbstractStorageService extends Disposable implements IStor if (typeof target === 'number') { if (keyTargets[key] !== target) { keyTargets[key] = target; - this.doStore(TARGET_KEY, JSON.stringify(keyTargets), scope); + this.getStorage(scope)?.set(TARGET_KEY, JSON.stringify(keyTargets)); } } @@ -334,7 +354,7 @@ export abstract class AbstractStorageService extends Disposable implements IStor else { if (typeof keyTargets[key] === 'number') { delete keyTargets[key]; - this.doStore(TARGET_KEY, JSON.stringify(keyTargets), scope); + this.getStorage(scope)?.set(TARGET_KEY, JSON.stringify(keyTargets)); } } } @@ -378,118 +398,62 @@ export abstract class AbstractStorageService extends Disposable implements IStor return this.getBoolean(IS_NEW_KEY, scope) === true; } - flush(): Promise { + async flush(): Promise { // Signal event to collect changes this._onWillSaveState.fire({ reason: WillSaveStateReason.NONE }); // Await flush - return this.doFlush(); + await Promises.settled([ + this.getStorage(StorageScope.GLOBAL)?.whenFlushed() ?? Promise.resolve(), + this.getStorage(StorageScope.WORKSPACE)?.whenFlushed() ?? Promise.resolve() + ]); + } + + async logStorage(): Promise { + const globalItems = this.getStorage(StorageScope.GLOBAL)?.items ?? new Map(); + const workspaceItems = this.getStorage(StorageScope.WORKSPACE)?.items ?? new Map(); + + return logStorage( + globalItems, + workspaceItems, + this.getLogDetails(StorageScope.GLOBAL) ?? '', + this.getLogDetails(StorageScope.WORKSPACE) ?? '' + ); } // --- abstract - abstract get(key: string, scope: StorageScope, fallbackValue: string): string; - abstract get(key: string, scope: StorageScope, fallbackValue?: string): string | undefined; + protected abstract getStorage(scope: StorageScope): IStorage | undefined; - abstract getBoolean(key: string, scope: StorageScope, fallbackValue: boolean): boolean; - abstract getBoolean(key: string, scope: StorageScope, fallbackValue?: boolean): boolean | undefined; - - abstract getNumber(key: string, scope: StorageScope, fallbackValue: number): number; - abstract getNumber(key: string, scope: StorageScope, fallbackValue?: number): number | undefined; - - protected abstract doStore(key: string, value: string | boolean | number, scope: StorageScope): void; - - protected abstract doRemove(key: string, scope: StorageScope): void; - - protected abstract doFlush(): Promise; + protected abstract getLogDetails(scope: StorageScope): string | undefined; abstract migrate(toWorkspace: IWorkspaceInitializationPayload): Promise; - - abstract logStorage(): void; } export class InMemoryStorageService extends AbstractStorageService { - private readonly globalCache = new Map(); - private readonly workspaceCache = new Map(); + private globalStorage = new Storage(new InMemoryStorageDatabase()); + private workspaceStorage = new Storage(new InMemoryStorageDatabase()); - private getCache(scope: StorageScope): Map { - return scope === StorageScope.GLOBAL ? this.globalCache : this.workspaceCache; + constructor() { + super(); + + this._register(this.workspaceStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.WORKSPACE, key))); + this._register(this.globalStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.GLOBAL, key))); } - get(key: string, scope: StorageScope, fallbackValue: string): string; - get(key: string, scope: StorageScope, fallbackValue?: string): string | undefined { - const value = this.getCache(scope).get(key); - - if (isUndefinedOrNull(value)) { - return fallbackValue; - } - - return value; + protected getStorage(scope: StorageScope): IStorage { + return scope === StorageScope.GLOBAL ? this.globalStorage : this.workspaceStorage; } - getBoolean(key: string, scope: StorageScope, fallbackValue: boolean): boolean; - getBoolean(key: string, scope: StorageScope, fallbackValue?: boolean): boolean | undefined { - const value = this.getCache(scope).get(key); - - if (isUndefinedOrNull(value)) { - return fallbackValue; - } - - return value === 'true'; - } - - getNumber(key: string, scope: StorageScope, fallbackValue: number): number; - getNumber(key: string, scope: StorageScope, fallbackValue?: number): number | undefined { - const value = this.getCache(scope).get(key); - - if (isUndefinedOrNull(value)) { - return fallbackValue; - } - - return parseInt(value, 10); - } - - protected doStore(key: string, value: string | boolean | number, scope: StorageScope): void { - - // Otherwise, convert to String and store - const valueStr = String(value); - - // Return early if value already set - const currentValue = this.getCache(scope).get(key); - if (currentValue === valueStr) { - return; - } - - // Update in cache - this.getCache(scope).set(key, valueStr); - - // Events - this.emitDidChangeValue(scope, key); - } - - protected doRemove(key: string, scope: StorageScope): void { - const wasDeleted = this.getCache(scope).delete(key); - if (!wasDeleted) { - return; // Return early if value already deleted - } - - // Events - this.emitDidChangeValue(scope, key); - } - - logStorage(): void { - logStorage(this.globalCache, this.workspaceCache, 'inMemory', 'inMemory'); + protected getLogDetails(scope: StorageScope): string | undefined { + return scope === StorageScope.GLOBAL ? 'inMemory (global)' : 'inMemory (workspace)'; } async migrate(toWorkspace: IWorkspaceInitializationPayload): Promise { // not supported } - - async doFlush(): Promise { } - - async close(): Promise { } } export async function logStorage(global: Map, workspace: Map, globalPath: string, workspacePath: string): Promise { diff --git a/src/vs/platform/storage/electron-sandbox/storageService2.ts b/src/vs/platform/storage/electron-sandbox/storageService2.ts index 8d7c315bd6c..c9bbecee81c 100644 --- a/src/vs/platform/storage/electron-sandbox/storageService2.ts +++ b/src/vs/platform/storage/electron-sandbox/storageService2.ts @@ -4,11 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; -import { StorageScope, WillSaveStateReason, logStorage, AbstractStorageService } from 'vs/platform/storage/common/storage'; +import { StorageScope, WillSaveStateReason, AbstractStorageService } from 'vs/platform/storage/common/storage'; import { Storage, IStorage } from 'vs/base/parts/storage/common/storage'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IEmptyWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier, IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces'; -import { assertIsDefined } from 'vs/base/common/types'; import { Promises, RunOnceScheduler, runWhenIdle } from 'vs/base/common/async'; import { mark } from 'vs/base/common/performance'; import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services'; @@ -72,41 +71,12 @@ export class NativeStorageService2 extends AbstractStorageService { this.periodicFlushScheduler.schedule(); } - get(key: string, scope: StorageScope, fallbackValue: string): string; - get(key: string, scope: StorageScope): string | undefined; - get(key: string, scope: StorageScope, fallbackValue?: string): string | undefined { - return this.getStorage(scope).get(key, fallbackValue); + protected getStorage(scope: StorageScope): IStorage | undefined { + return scope === StorageScope.GLOBAL ? this.globalStorage : this.workspaceStorage; } - getBoolean(key: string, scope: StorageScope, fallbackValue: boolean): boolean; - getBoolean(key: string, scope: StorageScope): boolean | undefined; - getBoolean(key: string, scope: StorageScope, fallbackValue?: boolean): boolean | undefined { - return this.getStorage(scope).getBoolean(key, fallbackValue); - } - - getNumber(key: string, scope: StorageScope, fallbackValue: number): number; - getNumber(key: string, scope: StorageScope): number | undefined; - getNumber(key: string, scope: StorageScope, fallbackValue?: number): number | undefined { - return this.getStorage(scope).getNumber(key, fallbackValue); - } - - protected doStore(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): void { - this.getStorage(scope).set(key, value); - } - - protected doRemove(key: string, scope: StorageScope): void { - this.getStorage(scope).delete(key); - } - - private getStorage(scope: StorageScope): IStorage { - return assertIsDefined(scope === StorageScope.GLOBAL ? this.globalStorage : this.workspaceStorage); - } - - protected async doFlush(): Promise { - await Promises.settled([ - this.globalStorage.whenFlushed(), - this.workspaceStorage?.whenFlushed() ?? Promise.resolve() - ]); + protected getLogDetails(scope: StorageScope): string | undefined { + return scope === StorageScope.GLOBAL ? this.environmentService.globalStorageHome.fsPath : this.workspace ? `${joinPath(this.environmentService.workspaceStorageHome, this.workspace.id, 'state.vscdb').fsPath} [!!! Experimental Main Storage !!!]` : undefined; } private doFlushWhenIdle(): void { @@ -142,15 +112,6 @@ export class NativeStorageService2 extends AbstractStorageService { ]); } - async logStorage(): Promise { - return logStorage( - this.globalStorage.items, - this.workspaceStorage ? this.workspaceStorage.items : new Map(), - this.environmentService.globalStorageHome.fsPath, - this.workspace ? `${joinPath(this.environmentService.workspaceStorageHome, this.workspace.id, 'state.vscdb').fsPath} [!!! Experimental Main Storage !!!]` : '' - ); - } - async migrate(toWorkspace: IWorkspaceInitializationPayload): Promise { // if (this.workspaceStoragePath === SQLiteStorageDatabase.IN_MEMORY_PATH) { // return; // no migration needed if running in memory diff --git a/src/vs/platform/storage/node/storageService.ts b/src/vs/platform/storage/node/storageService.ts index 111bbf4874c..316263b1b52 100644 --- a/src/vs/platform/storage/node/storageService.ts +++ b/src/vs/platform/storage/node/storageService.ts @@ -6,7 +6,7 @@ import { promises } from 'fs'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ILogService, LogLevel } from 'vs/platform/log/common/log'; -import { StorageScope, WillSaveStateReason, logStorage, IS_NEW_KEY, AbstractStorageService } from 'vs/platform/storage/common/storage'; +import { StorageScope, WillSaveStateReason, IS_NEW_KEY, AbstractStorageService } from 'vs/platform/storage/common/storage'; import { SQLiteStorageDatabase, ISQLiteStorageDatabaseLoggingOptions } from 'vs/base/parts/storage/node/storage'; import { Storage, IStorageDatabase, IStorage, StorageHint } from 'vs/base/parts/storage/common/storage'; import { mark } from 'vs/base/common/performance'; @@ -170,47 +170,12 @@ export class NativeStorageService extends AbstractStorageService { } } - get(key: string, scope: StorageScope, fallbackValue: string): string; - get(key: string, scope: StorageScope): string | undefined; - get(key: string, scope: StorageScope, fallbackValue?: string): string | undefined { - return this.getStorage(scope).get(key, fallbackValue); + protected getStorage(scope: StorageScope): IStorage | undefined { + return scope === StorageScope.GLOBAL ? this.globalStorage : this.workspaceStorage; } - getBoolean(key: string, scope: StorageScope, fallbackValue: boolean): boolean; - getBoolean(key: string, scope: StorageScope): boolean | undefined; - getBoolean(key: string, scope: StorageScope, fallbackValue?: boolean): boolean | undefined { - return this.getStorage(scope).getBoolean(key, fallbackValue); - } - - getNumber(key: string, scope: StorageScope, fallbackValue: number): number; - getNumber(key: string, scope: StorageScope): number | undefined; - getNumber(key: string, scope: StorageScope, fallbackValue?: number): number | undefined { - return this.getStorage(scope).getNumber(key, fallbackValue); - } - - protected doStore(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): void { - this.getStorage(scope).set(key, value); - } - - protected doRemove(key: string, scope: StorageScope): void { - this.getStorage(scope).delete(key); - } - - private getStorage(scope: StorageScope): IStorage { - return assertIsDefined(scope === StorageScope.GLOBAL ? this.globalStorage : this.workspaceStorage); - } - - protected async doFlush(): Promise { - const promises: Promise[] = []; - if (this.globalStorage) { - promises.push(this.globalStorage.whenFlushed()); - } - - if (this.workspaceStorage) { - promises.push(this.workspaceStorage.whenFlushed()); - } - - await Promises.settled(promises); + protected getLogDetails(scope: StorageScope): string | undefined { + return scope === StorageScope.GLOBAL ? this.environmentService.globalStorageHome.fsPath : this.workspaceStoragePath; } private doFlushWhenIdle(): void { @@ -246,21 +211,13 @@ export class NativeStorageService extends AbstractStorageService { ]); } - async logStorage(): Promise { - return logStorage( - this.globalStorage.items, - this.workspaceStorage ? this.workspaceStorage.items : new Map(), // Shared process storage does not has workspace storage - this.environmentService.globalStorageHome.fsPath, - this.workspaceStoragePath || ''); - } - async migrate(toWorkspace: IWorkspaceInitializationPayload): Promise { if (this.workspaceStoragePath === SQLiteStorageDatabase.IN_MEMORY_PATH) { return; // no migration needed if running in memory } // Close workspace DB to be able to copy - await this.getStorage(StorageScope.WORKSPACE).close(); + await this.workspaceStorage?.close(); // Prepare new workspace storage folder const result = await this.prepareWorkspaceStorageFolder(toWorkspace); From 8dbc14946b3b85e450eab5adb43a9654b16ef70b Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 16 Feb 2021 08:27:47 +0100 Subject: [PATCH 177/325] debt - consistent event names in main --- src/vs/code/electron-main/protocol.ts | 4 +-- .../platform/menubar/electron-main/menubar.ts | 10 +++--- .../electron-main/nativeHostMainService.ts | 4 +-- .../url/electron-main/electronUrlListener.ts | 2 +- .../platform/windows/electron-main/window.ts | 32 +++++++++---------- .../platform/windows/electron-main/windows.ts | 16 +++++----- .../electron-main/windowsMainService.ts | 30 ++++++++--------- .../electron-main/windowsStateHandler.ts | 4 +-- .../windows/test/electron-main/window.test.ts | 8 ++--- .../platform/workspaces/common/workspaces.ts | 2 +- .../workspacesHistoryMainService.ts | 16 +++++----- .../electron-main/workspacesMainService.ts | 2 +- .../workspacesManagementMainService.ts | 16 +++++----- .../browser/parts/titlebar/menubarControl.ts | 16 +++++----- .../workspaces/browser/workspacesService.ts | 2 +- .../test/browser/workbenchTestServices.ts | 2 +- 16 files changed, 83 insertions(+), 83 deletions(-) diff --git a/src/vs/code/electron-main/protocol.ts b/src/vs/code/electron-main/protocol.ts index 20644f2c9b9..3e535155c76 100644 --- a/src/vs/code/electron-main/protocol.ts +++ b/src/vs/code/electron-main/protocol.ts @@ -48,10 +48,10 @@ export class FileProtocolHandler extends Disposable { } injectWindowsMainService(windowsMainService: IWindowsMainService): void { - this._register(windowsMainService.onWindowReady(window => { + this._register(windowsMainService.onDidSignalReadyWindow(window => { if (window.config?.extensionDevelopmentPath || window.config?.extensionTestsPath) { const disposables = new DisposableStore(); - disposables.add(Event.any(window.onClose, window.onDestroy)(() => disposables.dispose())); + disposables.add(Event.any(window.onDidClose, window.onDidDestroy)(() => disposables.dispose())); // Allow access to extension development path if (window.config.extensionDevelopmentPath) { diff --git a/src/vs/platform/menubar/electron-main/menubar.ts b/src/vs/platform/menubar/electron-main/menubar.ts index 32f6b799eef..076f39011cb 100644 --- a/src/vs/platform/menubar/electron-main/menubar.ts +++ b/src/vs/platform/menubar/electron-main/menubar.ts @@ -168,9 +168,9 @@ export class Menubar { this.lifecycleMainService.onWillShutdown(() => this.willShutdown = true); // // Listen to some events from window service to update menu - this.windowsMainService.onWindowsCountChanged(e => this.onWindowsCountChanged(e)); - this.nativeHostMainService.onDidBlurWindow(() => this.onWindowFocusChange()); - this.nativeHostMainService.onDidFocusWindow(() => this.onWindowFocusChange()); + this.windowsMainService.onDidChangeWindowsCount(e => this.onDidChangeWindowsCount(e)); + this.nativeHostMainService.onDidBlurWindow(() => this.onDidChangeWindowFocus()); + this.nativeHostMainService.onDidFocusWindow(() => this.onDidChangeWindowFocus()); } private get currentEnableMenuBarMnemonics(): boolean { @@ -225,7 +225,7 @@ export class Menubar { } } - private onWindowsCountChanged(e: IWindowsCountChangedEvent): void { + private onDidChangeWindowsCount(e: IWindowsCountChangedEvent): void { if (!isMacintosh) { return; } @@ -237,7 +237,7 @@ export class Menubar { } } - private onWindowFocusChange(): void { + private onDidChangeWindowFocus(): void { if (!isMacintosh) { return; } diff --git a/src/vs/platform/native/electron-main/nativeHostMainService.ts b/src/vs/platform/native/electron-main/nativeHostMainService.ts index 406fd62d878..918ca38c2cb 100644 --- a/src/vs/platform/native/electron-main/nativeHostMainService.ts +++ b/src/vs/platform/native/electron-main/nativeHostMainService.ts @@ -76,14 +76,14 @@ export class NativeHostMainService extends Disposable implements INativeHostMain //#region Events - readonly onDidOpenWindow = Event.map(this.windowsMainService.onWindowOpened, window => window.id); + readonly onDidOpenWindow = Event.map(this.windowsMainService.onDidOpenWindow, window => window.id); readonly onDidMaximizeWindow = Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-maximize', (event, window: BrowserWindow) => window.id), windowId => !!this.windowsMainService.getWindowById(windowId)); readonly onDidUnmaximizeWindow = Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-unmaximize', (event, window: BrowserWindow) => window.id), windowId => !!this.windowsMainService.getWindowById(windowId)); readonly onDidBlurWindow = Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-blur', (event, window: BrowserWindow) => window.id), windowId => !!this.windowsMainService.getWindowById(windowId)); readonly onDidFocusWindow = Event.any( - Event.map(Event.filter(Event.map(this.windowsMainService.onWindowsCountChanged, () => this.windowsMainService.getLastActiveWindow()), window => !!window), window => window!.id), + Event.map(Event.filter(Event.map(this.windowsMainService.onDidChangeWindowsCount, () => this.windowsMainService.getLastActiveWindow()), window => !!window), window => window!.id), Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-focus', (event, window: BrowserWindow) => window.id), windowId => !!this.windowsMainService.getWindowById(windowId)) ); diff --git a/src/vs/platform/url/electron-main/electronUrlListener.ts b/src/vs/platform/url/electron-main/electronUrlListener.ts index 50ca2ea249c..9ae6d13d2af 100644 --- a/src/vs/platform/url/electron-main/electronUrlListener.ts +++ b/src/vs/platform/url/electron-main/electronUrlListener.ts @@ -82,7 +82,7 @@ export class ElectronURLListener { if (isWindowReady) { this.flush(); } else { - Event.once(windowsMainService.onWindowReady)(this.flush, this, this.disposables); + Event.once(windowsMainService.onDidSignalReadyWindow)(this.flush, this, this.disposables); } } diff --git a/src/vs/platform/windows/electron-main/window.ts b/src/vs/platform/windows/electron-main/window.ts index 7f42a6c6ae8..c437ab35c47 100644 --- a/src/vs/platform/windows/electron-main/window.ts +++ b/src/vs/platform/windows/electron-main/window.ts @@ -80,17 +80,17 @@ export class CodeWindow extends Disposable implements ICodeWindow { private static readonly MAX_URL_LENGTH = 2 * ByteSize.MB; // https://cs.chromium.org/chromium/src/url/url_constants.cc?l=32 - private readonly _onLoad = this._register(new Emitter()); - readonly onLoad = this._onLoad.event; + private readonly _onDidLoad = this._register(new Emitter()); + readonly onDidLoad = this._onDidLoad.event; - private readonly _onReady = this._register(new Emitter()); - readonly onReady = this._onReady.event; + private readonly _onDidSignalReady = this._register(new Emitter()); + readonly onDidSignalReady = this._onDidSignalReady.event; - private readonly _onClose = this._register(new Emitter()); - readonly onClose = this._onClose.event; + private readonly _onDidClose = this._register(new Emitter()); + readonly onDidClose = this._onDidClose.event; - private readonly _onDestroy = this._register(new Emitter()); - readonly onDestroy = this._onDestroy.event; + private readonly _onDidDestroy = this._register(new Emitter()); + readonly onDidDestroy = this._onDidDestroy.event; private hiddenTitleBarStyle: boolean | undefined; private showTimeoutHandle: NodeJS.Timeout | undefined; @@ -367,7 +367,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { } // Events - this._onReady.fire(); + this._onDidSignalReady.fire(); } ready(): Promise { @@ -395,8 +395,8 @@ export class CodeWindow extends Disposable implements ICodeWindow { resolve(); } - const closeListener = this.onClose(() => handle()); - const loadListener = this.onLoad(() => handle()); + const closeListener = this.onDidClose(() => handle()); + const loadListener = this.onDidLoad(() => handle()); }); } @@ -409,7 +409,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { // Window close this._win.on('closed', () => { - this._onClose.fire(); + this._onDidClose.fire(); this.dispose(); }); @@ -538,7 +538,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { this._register(this.configurationService.onDidChangeConfiguration(() => this.onConfigurationUpdated())); // Handle Workspace events - this._register(this.workspacesManagementMainService.onUntitledWorkspaceDeleted(e => this.onUntitledWorkspaceDeleted(e))); + this._register(this.workspacesManagementMainService.onDidDeleteUntitledWorkspace(e => this.onDidDeleteUntitledWorkspace(e))); // Inject headers when requests are incoming const urls = ['https://marketplace.visualstudio.com/*', 'https://*.vsassets.io/*']; @@ -636,11 +636,11 @@ export class CodeWindow extends Disposable implements ICodeWindow { } private destroyWindow(): void { - this._onDestroy.fire(); // 'close' event will not be fired on destroy(), so signal crash via explicit event + this._onDidDestroy.fire(); // 'close' event will not be fired on destroy(), so signal crash via explicit event this._win.destroy(); // make sure to destroy the window as it has crashed } - private onUntitledWorkspaceDeleted(workspace: IWorkspaceIdentifier): void { + private onDidDeleteUntitledWorkspace(workspace: IWorkspaceIdentifier): void { // Make sure to update our workspace config if we detect that it // was deleted @@ -761,7 +761,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { } // Event - this._onLoad.fire(); + this._onDidLoad.fire(); } async reload(cli?: NativeParsedArgs): Promise { diff --git a/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts index c309ff263f4..89ade1c8667 100644 --- a/src/vs/platform/windows/electron-main/windows.ts +++ b/src/vs/platform/windows/electron-main/windows.ts @@ -62,10 +62,10 @@ export const enum WindowMode { export interface ICodeWindow extends IDisposable { - readonly onLoad: Event; - readonly onReady: Event; - readonly onClose: Event; - readonly onDestroy: Event; + readonly onDidLoad: Event; + readonly onDidSignalReady: Event; + readonly onDidClose: Event; + readonly onDidDestroy: Event; readonly whenClosedOrLoaded: Promise; @@ -132,11 +132,11 @@ export interface IWindowsMainService { readonly _serviceBrand: undefined; - readonly onWindowsCountChanged: Event; + readonly onDidChangeWindowsCount: Event; - readonly onWindowOpened: Event; - readonly onWindowReady: Event; - readonly onWindowDestroyed: Event; + readonly onDidOpenWindow: Event; + readonly onDidSignalReadyWindow: Event; + readonly onDidDestroyWindow: Event; open(openConfig: IOpenConfiguration): ICodeWindow[]; openEmptyWindow(openConfig: IOpenEmptyConfiguration, options?: IOpenEmptyWindowOptions): ICodeWindow[]; diff --git a/src/vs/platform/windows/electron-main/windowsMainService.ts b/src/vs/platform/windows/electron-main/windowsMainService.ts index c7625528cf4..c1244908aa5 100644 --- a/src/vs/platform/windows/electron-main/windowsMainService.ts +++ b/src/vs/platform/windows/electron-main/windowsMainService.ts @@ -118,17 +118,17 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic private static readonly WINDOWS: ICodeWindow[] = []; - private readonly _onWindowOpened = this._register(new Emitter()); - readonly onWindowOpened = this._onWindowOpened.event; + private readonly _onDidOpenWindow = this._register(new Emitter()); + readonly onDidOpenWindow = this._onDidOpenWindow.event; - private readonly _onWindowReady = this._register(new Emitter()); - readonly onWindowReady = this._onWindowReady.event; + private readonly _onDidSignalReadyWindow = this._register(new Emitter()); + readonly onDidSignalReadyWindow = this._onDidSignalReadyWindow.event; - private readonly _onWindowDestroyed = this._register(new Emitter()); - readonly onWindowDestroyed = this._onWindowDestroyed.event; + private readonly _onDidDestroyWindow = this._register(new Emitter()); + readonly onDidDestroyWindow = this._onDidDestroyWindow.event; - private readonly _onWindowsCountChanged = this._register(new Emitter()); - readonly onWindowsCountChanged = this._onWindowsCountChanged.event; + private readonly _onDidChangeWindowsCount = this._register(new Emitter()); + readonly onDidChangeWindowsCount = this._onDidChangeWindowsCount.event; private readonly windowsStateHandler = this._register(new WindowsStateHandler(this, this.stateService, this.lifecycleMainService, this.logService, this.configurationService)); @@ -155,7 +155,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic private registerListeners(): void { // Signal a window is ready after having entered a workspace - this._register(this.workspacesManagementMainService.onWorkspaceEntered(event => this._onWindowReady.fire(event.window))); + this._register(this.workspacesManagementMainService.onDidEnterWorkspace(event => this._onDidSignalReadyWindow.fire(event.window))); } openEmptyWindow(openConfig: IOpenEmptyConfiguration, options?: IOpenEmptyWindowOptions): ICodeWindow[] { @@ -1191,15 +1191,15 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic WindowsMainService.WINDOWS.push(createdWindow); // Indicate new window via event - this._onWindowOpened.fire(createdWindow); + this._onDidOpenWindow.fire(createdWindow); // Indicate number change via event - this._onWindowsCountChanged.fire({ oldCount: this.getWindowCount() - 1, newCount: this.getWindowCount() }); + this._onDidChangeWindowsCount.fire({ oldCount: this.getWindowCount() - 1, newCount: this.getWindowCount() }); // Window Events - once(createdWindow.onReady)(() => this._onWindowReady.fire(createdWindow)); - once(createdWindow.onClose)(() => this.onWindowClosed(createdWindow)); - once(createdWindow.onDestroy)(() => this._onWindowDestroyed.fire(createdWindow)); + once(createdWindow.onDidSignalReady)(() => this._onDidSignalReadyWindow.fire(createdWindow)); + once(createdWindow.onDidClose)(() => this.onWindowClosed(createdWindow)); + once(createdWindow.onDidDestroy)(() => this._onDidDestroyWindow.fire(createdWindow)); createdWindow.win.webContents.removeAllListeners('devtools-reload-page'); // remove built in listener so we can handle this on our own createdWindow.win.webContents.on('devtools-reload-page', () => this.lifecycleMainService.reload(createdWindow)); @@ -1264,7 +1264,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic WindowsMainService.WINDOWS.splice(index, 1); // Emit - this._onWindowsCountChanged.fire({ oldCount: this.getWindowCount() + 1, newCount: this.getWindowCount() }); + this._onDidChangeWindowsCount.fire({ oldCount: this.getWindowCount() + 1, newCount: this.getWindowCount() }); } getFocusedWindow(): ICodeWindow | undefined { diff --git a/src/vs/platform/windows/electron-main/windowsStateHandler.ts b/src/vs/platform/windows/electron-main/windowsStateHandler.ts index b0e50c85ff4..cc3e5457601 100644 --- a/src/vs/platform/windows/electron-main/windowsStateHandler.ts +++ b/src/vs/platform/windows/electron-main/windowsStateHandler.ts @@ -85,7 +85,7 @@ export class WindowsStateHandler extends Disposable { // Handle various lifecycle events around windows this.lifecycleMainService.onBeforeWindowClose(window => this.onBeforeWindowClose(window)); this.lifecycleMainService.onBeforeShutdown(() => this.onBeforeShutdown()); - this.windowsMainService.onWindowsCountChanged(e => { + this.windowsMainService.onDidChangeWindowsCount(e => { if (e.newCount - e.oldCount > 0) { // clear last closed window state when a new window opens. this helps on macOS where // otherwise closing the last window, opening a new window and then quitting would @@ -95,7 +95,7 @@ export class WindowsStateHandler extends Disposable { }); // try to save state before destroy because close will not fire - this.windowsMainService.onWindowDestroyed(window => this.onBeforeWindowClose(window)); + this.windowsMainService.onDidDestroyWindow(window => this.onBeforeWindowClose(window)); } // Note that onBeforeShutdown() and onBeforeWindowClose() are fired in different order depending on the OS: diff --git a/src/vs/platform/windows/test/electron-main/window.test.ts b/src/vs/platform/windows/test/electron-main/window.test.ts index 94ae6eea848..b1aa09b7e13 100644 --- a/src/vs/platform/windows/test/electron-main/window.test.ts +++ b/src/vs/platform/windows/test/electron-main/window.test.ts @@ -32,10 +32,10 @@ suite('WindowsFinder', () => { function createTestCodeWindow(options: { lastFocusTime: number, openedFolderUri?: URI, openedWorkspace?: IWorkspaceIdentifier }): ICodeWindow { return new class implements ICodeWindow { - onLoad: Event = Event.None; - onReady: Event = Event.None; - onClose: Event = Event.None; - onDestroy: Event = Event.None; + onDidLoad: Event = Event.None; + onDidSignalReady: Event = Event.None; + onDidClose: Event = Event.None; + onDidDestroy: Event = Event.None; whenClosedOrLoaded: Promise = Promise.resolve(); id: number = -1; win: Electron.BrowserWindow = undefined!; diff --git a/src/vs/platform/workspaces/common/workspaces.ts b/src/vs/platform/workspaces/common/workspaces.ts index 897a204578e..8be3cea72d7 100644 --- a/src/vs/platform/workspaces/common/workspaces.ts +++ b/src/vs/platform/workspaces/common/workspaces.ts @@ -45,7 +45,7 @@ export interface IWorkspacesService { getWorkspaceIdentifier(workspacePath: URI): Promise; // Workspaces History - readonly onRecentlyOpenedChange: Event; + readonly onDidChangeRecentlyOpened: Event; addRecentlyOpened(recents: IRecent[]): Promise; removeRecentlyOpened(workspaces: URI[]): Promise; clearRecentlyOpened(): Promise; diff --git a/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts index bd16a20bbb8..30b358c4ce8 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts @@ -30,7 +30,7 @@ export interface IWorkspacesHistoryMainService { readonly _serviceBrand: undefined; - readonly onRecentlyOpenedChange: CommonEvent; + readonly onDidChangeRecentlyOpened: CommonEvent; addRecentlyOpened(recents: IRecent[]): void; getRecentlyOpened(include?: ICodeWindow): IRecentlyOpened; @@ -57,8 +57,8 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa declare readonly _serviceBrand: undefined; - private readonly _onRecentlyOpenedChange = this._register(new Emitter()); - readonly onRecentlyOpenedChange: CommonEvent = this._onRecentlyOpenedChange.event; + private readonly _onDidChangeRecentlyOpened = this._register(new Emitter()); + readonly onDidChangeRecentlyOpened: CommonEvent = this._onDidChangeRecentlyOpened.event; private readonly macOSRecentDocumentsUpdater = this._register(new ThrottledDelayer(800)); @@ -80,7 +80,7 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.handleWindowsJumpList()); // Add to history when entering workspace - this._register(this.workspacesManagementMainService.onWorkspaceEntered(event => this.addRecentlyOpened([{ workspace: event.workspace }]))); + this._register(this.workspacesManagementMainService.onDidEnterWorkspace(event => this.addRecentlyOpened([{ workspace: event.workspace }]))); } private handleWindowsJumpList(): void { @@ -89,7 +89,7 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa } this.updateWindowsJumpList(); - this._register(this.onRecentlyOpenedChange(() => this.updateWindowsJumpList())); + this._register(this.onDidChangeRecentlyOpened(() => this.updateWindowsJumpList())); } addRecentlyOpened(recentToAdd: IRecent[]): void { @@ -139,7 +139,7 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa } this.saveRecentlyOpened({ workspaces, files }); - this._onRecentlyOpenedChange.fire(); + this._onDidChangeRecentlyOpened.fire(); // Schedule update to recent documents on macOS dock if (isMacintosh) { @@ -165,7 +165,7 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa if (workspaces.length !== mru.workspaces.length || files.length !== mru.files.length) { this.saveRecentlyOpened({ files, workspaces }); - this._onRecentlyOpenedChange.fire(); + this._onDidChangeRecentlyOpened.fire(); // Schedule update to recent documents on macOS dock if (isMacintosh) { @@ -238,7 +238,7 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa app.clearRecentDocuments(); // Event - this._onRecentlyOpenedChange.fire(); + this._onDidChangeRecentlyOpened.fire(); } getRecentlyOpened(include?: ICodeWindow): IRecentlyOpened { diff --git a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts index 5328a07dd5e..67a5e54db3f 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts @@ -50,7 +50,7 @@ export class WorkspacesMainService implements AddFirstParameterToFunctions { return this.workspacesHistoryMainService.getRecentlyOpened(this.windowsMainService.getWindowById(windowId)); diff --git a/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts index c9d22ba0af3..d738633f973 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts @@ -38,8 +38,8 @@ export interface IWorkspacesManagementMainService { readonly _serviceBrand: undefined; - readonly onUntitledWorkspaceDeleted: Event; - readonly onWorkspaceEntered: Event; + readonly onDidDeleteUntitledWorkspace: Event; + readonly onDidEnterWorkspace: Event; enterWorkspace(intoWindow: ICodeWindow, openedWindows: ICodeWindow[], path: URI): Promise; @@ -67,11 +67,11 @@ export class WorkspacesManagementMainService extends Disposable implements IWork private readonly untitledWorkspacesHome = this.environmentService.untitledWorkspacesHome; // local URI that contains all untitled workspaces - private readonly _onUntitledWorkspaceDeleted = this._register(new Emitter()); - readonly onUntitledWorkspaceDeleted: Event = this._onUntitledWorkspaceDeleted.event; + private readonly _onDidDeleteUntitledWorkspace = this._register(new Emitter()); + readonly onDidDeleteUntitledWorkspace: Event = this._onDidDeleteUntitledWorkspace.event; - private readonly _onWorkspaceEntered = this._register(new Emitter()); - readonly onWorkspaceEntered: Event = this._onWorkspaceEntered.event; + private readonly _onDidEnterWorkspace = this._register(new Emitter()); + readonly onDidEnterWorkspace: Event = this._onDidEnterWorkspace.event; constructor( @IEnvironmentMainService private readonly environmentService: IEnvironmentMainService, @@ -198,7 +198,7 @@ export class WorkspacesManagementMainService extends Disposable implements IWork this.doDeleteUntitledWorkspaceSync(workspace); // Event - this._onUntitledWorkspaceDeleted.fire(workspace); + this._onDidDeleteUntitledWorkspace.fire(workspace); } async deleteUntitledWorkspace(workspace: IWorkspaceIdentifier): Promise { @@ -260,7 +260,7 @@ export class WorkspacesManagementMainService extends Disposable implements IWork } // Emit as event - this._onWorkspaceEntered.fire({ window, workspace: result.workspace }); + this._onDidEnterWorkspace.fire({ window, workspace: result.workspace }); return result; } diff --git a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts index f3587a51a51..96f49a70965 100644 --- a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts +++ b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts @@ -127,13 +127,13 @@ export abstract class MenubarControl extends Disposable { this.updateService.onStateChange(() => this.onUpdateStateChange()); // Listen for changes in recently opened menu - this._register(this.workspacesService.onRecentlyOpenedChange(() => { this.onRecentlyOpenedChange(); })); + this._register(this.workspacesService.onDidChangeRecentlyOpened(() => { this.onDidChangeRecentlyOpened(); })); // Listen to keybindings change this._register(this.keybindingService.onDidUpdateKeybindings(() => this.updateMenubar())); // Update recent menu items on formatter registration - this._register(this.labelService.onDidChangeFormatters(() => { this.onRecentlyOpenedChange(); })); + this._register(this.labelService.onDidChangeFormatters(() => { this.onDidChangeRecentlyOpened(); })); } protected updateMenubar(): void { @@ -189,7 +189,7 @@ export abstract class MenubarControl extends Disposable { protected onDidChangeWindowFocus(hasFocus: boolean): void { // When we regain focus, update the recent menu items if (hasFocus) { - this.onRecentlyOpenedChange(); + this.onDidChangeRecentlyOpened(); } } @@ -205,7 +205,7 @@ export abstract class MenubarControl extends Disposable { // Since we try not update when hidden, we should // try to update the recently opened list on visibility changes if (event.affectsConfiguration('window.menuBarVisibility')) { - this.onRecentlyOpenedChange(); + this.onDidChangeRecentlyOpened(); } } @@ -213,7 +213,7 @@ export abstract class MenubarControl extends Disposable { return isMacintosh && isNative ? false : getMenuBarVisibility(this.configurationService) === 'hidden'; } - protected onRecentlyOpenedChange(): void { + protected onDidChangeRecentlyOpened(): void { // Do not update recently opened when the menubar is hidden #108712 if (!this.menubarHidden) { @@ -543,7 +543,7 @@ export class CustomMenubarControl extends MenubarControl { private onDidVisibilityChange(visible: boolean): void { this.visible = visible; - this.onRecentlyOpenedChange(); + this.onDidChangeRecentlyOpened(); this._onVisibilityChange.fire(visible); } @@ -765,12 +765,12 @@ export class CustomMenubarControl extends MenubarControl { super.onUpdateStateChange(); } - protected onRecentlyOpenedChange(): void { + protected onDidChangeRecentlyOpened(): void { if (!this.visible) { return; } - super.onRecentlyOpenedChange(); + super.onDidChangeRecentlyOpened(); } protected onUpdateKeybindings(): void { diff --git a/src/vs/workbench/services/workspaces/browser/workspacesService.ts b/src/vs/workbench/services/workspaces/browser/workspacesService.ts index 6d6b1d77002..28d39cec2f6 100644 --- a/src/vs/workbench/services/workspaces/browser/workspacesService.ts +++ b/src/vs/workbench/services/workspaces/browser/workspacesService.ts @@ -26,7 +26,7 @@ export class BrowserWorkspacesService extends Disposable implements IWorkspacesS declare readonly _serviceBrand: undefined; private readonly _onRecentlyOpenedChange = this._register(new Emitter()); - readonly onRecentlyOpenedChange = this._onRecentlyOpenedChange.event; + readonly onDidChangeRecentlyOpened = this._onRecentlyOpenedChange.event; constructor( @IStorageService private readonly storageService: IStorageService, diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index e2d267e6704..aa394668a9b 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -1413,7 +1413,7 @@ export class TestTextFileEditorModelManager extends TextFileEditorModelManager { export class TestWorkspacesService implements IWorkspacesService { _serviceBrand: undefined; - onRecentlyOpenedChange = Event.None; + onDidChangeRecentlyOpened = Event.None; async createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise { throw new Error('Method not implemented.'); } async deleteUntitledWorkspace(workspace: IWorkspaceIdentifier): Promise { } From f606206cc8f18650fd0378600c4ee30be2c951c9 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 16 Feb 2021 08:33:34 +0100 Subject: [PATCH 178/325] debt - consistently refer to main services --- src/vs/code/electron-main/app.ts | 52 +++++++++---------- src/vs/code/electron-main/main.ts | 40 +++++++------- .../backup/electron-main/backupMainService.ts | 6 +-- .../platform/driver/electron-main/driver.ts | 4 +- .../issue/electron-main/issueMainService.ts | 8 +-- .../platform/menubar/electron-main/menubar.ts | 6 +-- .../electron-main/nativeHostMainService.ts | 24 ++++----- .../electron-main/sharedProcess.ts | 10 ++-- .../electron-main/abstractUpdateService.ts | 6 +-- .../electron-main/updateService.darwin.ts | 4 +- .../electron-main/updateService.linux.ts | 4 +- .../electron-main/updateService.snap.ts | 8 +-- .../electron-main/updateService.win32.ts | 4 +- .../url/electron-main/electronUrlListener.ts | 4 +- .../electron-main/windowsMainService.ts | 12 ++--- .../workspacesHistoryMainService.ts | 4 +- .../workspacesManagementMainService.ts | 10 ++-- .../workspacesManagementMainService.test.ts | 6 +-- 18 files changed, 106 insertions(+), 106 deletions(-) diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index c9aa9a1384e..1a378fd011f 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -102,7 +102,7 @@ export class CodeApplication extends Disposable { private readonly userEnv: IProcessEnvironment, @IInstantiationService private readonly mainInstantiationService: IInstantiationService, @ILogService private readonly logService: ILogService, - @IEnvironmentMainService private readonly environmentService: IEnvironmentMainService, + @IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService, @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, @IConfigurationService private readonly configurationService: IConfigurationService, @IStateService private readonly stateService: IStateService, @@ -168,7 +168,7 @@ export class CodeApplication extends Disposable { event.preventDefault(); }); app.on('remote-get-current-web-contents', event => { - if (this.environmentService.args.driver) { + if (this.environmentMainService.args.driver) { return; // the driver needs access to web contents } @@ -190,7 +190,7 @@ export class CodeApplication extends Disposable { } const srcUri = uri.fsPath.toLowerCase(); - const rootUri = URI.file(this.environmentService.appRoot).fsPath.toLowerCase(); + const rootUri = URI.file(this.environmentMainService.appRoot).fsPath.toLowerCase(); return srcUri.startsWith(rootUri + sep); }; @@ -255,7 +255,7 @@ export class CodeApplication extends Disposable { runningTimeout = setTimeout(() => { this.windowsMainService?.open({ context: OpenContext.DOCK /* can also be opening from finder while app is running */, - cli: this.environmentService.args, + cli: this.environmentMainService.args, urisToOpen: macOpenFileURIs, gotoLineMode: false, preferNewWindow: true /* dropping on the dock or opening from finder prefers to open in a new window */ @@ -328,7 +328,7 @@ export class CodeApplication extends Disposable { args = window.config; env = { ...process.env, ...window.config.userEnv }; } else { - args = this.environmentService.args; + args = this.environmentMainService.args; env = process.env; } @@ -376,7 +376,7 @@ export class CodeApplication extends Disposable { } } - if (typeof path !== 'string' || !isAbsolute(path) || !isEqualOrParent(path, this.environmentService.cachedLanguagesPath, !isLinux)) { + if (typeof path !== 'string' || !isAbsolute(path) || !isEqualOrParent(path, this.environmentMainService.cachedLanguagesPath, !isLinux)) { return undefined; } @@ -404,8 +404,8 @@ export class CodeApplication extends Disposable { async startup(): Promise { this.logService.debug('Starting VS Code'); - this.logService.debug(`from: ${this.environmentService.appRoot}`); - this.logService.debug('args:', this.environmentService.args); + this.logService.debug(`from: ${this.environmentMainService.appRoot}`); + this.logService.debug('args:', this.environmentMainService.args); // Make sure we associate the program with the app user model id // This will help Windows to associate the running program with @@ -448,10 +448,10 @@ export class CodeApplication extends Disposable { const appInstantiationService = await this.initServices(machineId, sharedProcess, sharedProcessReady); // Create driver - if (this.environmentService.driverHandle) { - const server = await serveDriver(mainProcessElectronServer, this.environmentService.driverHandle, this.environmentService, appInstantiationService); + if (this.environmentMainService.driverHandle) { + const server = await serveDriver(mainProcessElectronServer, this.environmentMainService.driverHandle, this.environmentMainService, appInstantiationService); - this.logService.info('Driver started at:', this.environmentService.driverHandle); + this.logService.info('Driver started at:', this.environmentMainService.driverHandle); this._register(server); } @@ -468,7 +468,7 @@ export class CodeApplication extends Disposable { appInstantiationService.invokeFunction(accessor => this.afterWindowOpen(accessor)); // Tracing: Stop tracing after windows are ready if enabled - if (this.environmentService.args.trace) { + if (this.environmentMainService.args.trace) { appInstantiationService.invokeFunction(accessor => this.stopTracingEventually(accessor, windows)); } } @@ -509,7 +509,7 @@ export class CodeApplication extends Disposable { // Spawn shared process after the first window has opened and 3s have passed this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => { this._register(new RunOnceScheduler(async () => { - sharedProcess.spawn(await resolveShellEnv(this.logService, this.environmentService.args, process.env)); + sharedProcess.spawn(await resolveShellEnv(this.logService, this.environmentMainService.args, process.env)); }, 3000)).schedule(); }); @@ -583,18 +583,18 @@ export class CodeApplication extends Disposable { services.set(IStorageMainService, new SyncDescriptor(StorageMainService)); // Backups - const backupMainService = new BackupMainService(this.environmentService, this.configurationService, this.logService); + const backupMainService = new BackupMainService(this.environmentMainService, this.configurationService, this.logService); services.set(IBackupMainService, backupMainService); // URL handling services.set(IURLService, new SyncDescriptor(NativeURLService)); // Telemetry - if (!this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!product.enableTelemetry) { + if (!this.environmentMainService.isExtensionDevelopment && !this.environmentMainService.args['disable-telemetry'] && !!product.enableTelemetry) { const channel = getDelayedChannel(sharedProcessReady.then(client => client.getChannel('telemetryAppender'))); const appender = new TelemetryAppenderClient(channel); - const commonProperties = resolveCommonProperties(this.fileService, release(), process.arch, product.commit, product.version, machineId, product.msftInternalDomains, this.environmentService.installSourcePath); - const piiPaths = [this.environmentService.appRoot, this.environmentService.extensionsPath]; + const commonProperties = resolveCommonProperties(this.fileService, release(), process.arch, product.commit, product.version, machineId, product.msftInternalDomains, this.environmentMainService.installSourcePath); + const piiPaths = [this.environmentMainService.appRoot, this.environmentMainService.extensionsPath]; const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths, sendErrorTelemetry: true }; services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config])); @@ -697,7 +697,7 @@ export class CodeApplication extends Disposable { const pendingWindowOpenablesFromProtocolLinks: IWindowOpenable[] = []; const pendingProtocolLinksToHandle = [ // Windows/Linux: protocol handler invokes CLI with --open-url - ...this.environmentService.args['open-url'] ? this.environmentService.args._urls || [] : [], + ...this.environmentMainService.args['open-url'] ? this.environmentMainService.args._urls || [] : [], // macOS: open-url events ...((global).getOpenUrls() || []) as string[] @@ -734,7 +734,7 @@ export class CodeApplication extends Disposable { // or open new windows. The URL handler will be invoked from // protocol invocations outside of VSCode. const app = this; - const environmentService = this.environmentService; + const environmentService = this.environmentMainService; urlService.registerHandler({ async handleURL(uri: URI, options?: IOpenURLOptions): Promise { @@ -789,10 +789,10 @@ export class CodeApplication extends Disposable { urlService.registerHandler(new URLHandlerChannelClient(urlHandlerChannel)); // Watch Electron URLs and forward them to the UrlService - this._register(new ElectronURLListener(pendingProtocolLinksToHandle, urlService, windowsMainService, this.environmentService)); + this._register(new ElectronURLListener(pendingProtocolLinksToHandle, urlService, windowsMainService, this.environmentMainService)); // Open our first window - const args = this.environmentService.args; + const args = this.environmentMainService.args; const macOpenFiles: string[] = (global).macOpenFiles; const context = isLaunchedFromCli(process.env) ? OpenContext.CLI : OpenContext.DESKTOP; const hasCliArgs = args._.length; @@ -862,7 +862,7 @@ export class CodeApplication extends Disposable { mnemonicButtonLabel(localize({ key: 'cancel', comment: ['&& denotes a mnemonic'] }, "&&No")), ], cancelId: 1, - message: localize('confirmOpenMessage', "An external application wants to open '{0}' in {1}. Do you want to open this file or folder?", getPathLabel(uri.fsPath, this.environmentService), product.nameShort), + message: localize('confirmOpenMessage', "An external application wants to open '{0}' in {1}. Do you want to open this file or folder?", getPathLabel(uri.fsPath, this.environmentMainService), product.nameShort), detail: localize('confirmOpenDetail', "If you did not initiate this request, it may represent an attempted attack on your system. Unless you took an explicit action to initiate this request, you should press 'No'"), noLink: true }); @@ -958,13 +958,13 @@ export class CodeApplication extends Disposable { } // Start to fetch shell environment (if needed) after window has opened - resolveShellEnv(this.logService, this.environmentService.args, process.env); + resolveShellEnv(this.logService, this.environmentMainService.args, process.env); // If enable-crash-reporter argv is undefined then this is a fresh start, // based on telemetry.enableCrashreporter settings, generate a UUID which // will be used as crash reporter id and also update the json file. try { - const argvContent = await this.fileService.readFile(this.environmentService.argvResource); + const argvContent = await this.fileService.readFile(this.environmentMainService.argvResource); const argvString = argvContent.value.toString(); const argvJSON = JSON.parse(stripComments(argvString)); if (argvJSON['enable-crash-reporter'] === undefined) { @@ -982,7 +982,7 @@ export class CodeApplication extends Disposable { ]; const newArgvString = argvString.substring(0, argvString.length - 2).concat(',\n', additionalArgvContent.join('\n')); - await this.fileService.writeFile(this.environmentService.argvResource, VSBuffer.fromString(newArgvString)); + await this.fileService.writeFile(this.environmentMainService.argvResource, VSBuffer.fromString(newArgvString)); } } catch (error) { this.logService.error(error); @@ -1002,7 +1002,7 @@ export class CodeApplication extends Disposable { recordingStopped = true; // only once - const path = await contentTracing.stopRecording(joinPath(this.environmentService.userHome, `${product.applicationName}-${Math.random().toString(16).slice(-4)}.trace.txt`).fsPath); + const path = await contentTracing.stopRecording(joinPath(this.environmentMainService.userHome, `${product.applicationName}-${Math.random().toString(16).slice(-4)}.trace.txt`).fsPath); if (!timeout) { dialogMainService.showMessageBox({ diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index 0ccc3092bd4..7cbdd078f09 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -181,9 +181,9 @@ class CodeMain { return [new InstantiationService(services, true), instanceEnvironment, environmentService, configurationService, stateService, bufferLogService]; } - private patchEnvironment(environmentService: IEnvironmentMainService): IProcessEnvironment { + private patchEnvironment(environmentMainService: IEnvironmentMainService): IProcessEnvironment { const instanceEnvironment: IProcessEnvironment = { - VSCODE_IPC_HOOK: environmentService.mainIPCHandle + VSCODE_IPC_HOOK: environmentMainService.mainIPCHandle }; ['VSCODE_NLS_CONFIG', 'VSCODE_PORTABLE'].forEach(key => { @@ -198,16 +198,16 @@ class CodeMain { return instanceEnvironment; } - private initServices(environmentService: IEnvironmentMainService, configurationService: ConfigurationService, stateService: StateService): Promise { + private initServices(environmentMainService: IEnvironmentMainService, configurationService: ConfigurationService, stateService: StateService): Promise { // Environment service (paths) const environmentServiceInitialization = Promise.all([ - environmentService.extensionsPath, - environmentService.nodeCachedDataDir, - environmentService.logsPath, - environmentService.globalStorageHome.fsPath, - environmentService.workspaceStorageHome.fsPath, - environmentService.backupHome + environmentMainService.extensionsPath, + environmentMainService.nodeCachedDataDir, + environmentMainService.logsPath, + environmentMainService.globalStorageHome.fsPath, + environmentMainService.workspaceStorageHome.fsPath, + environmentMainService.backupHome ].map(path => path ? promises.mkdir(path, { recursive: true }) : undefined)); // Configuration service @@ -219,14 +219,14 @@ class CodeMain { return Promise.all([environmentServiceInitialization, configurationServiceInitialization, stateServiceInitialization]); } - private async doStartup(args: NativeParsedArgs, logService: ILogService, environmentService: IEnvironmentMainService, lifecycleMainService: ILifecycleMainService, instantiationService: IInstantiationService, retry: boolean): Promise { + private async doStartup(args: NativeParsedArgs, logService: ILogService, environmentMainService: IEnvironmentMainService, lifecycleMainService: ILifecycleMainService, instantiationService: IInstantiationService, retry: boolean): Promise { // Try to setup a server for running. If that succeeds it means // we are the first instance to startup. Otherwise it is likely // that another instance is already running. let mainProcessNodeIpcServer: NodeIPCServer; try { - mainProcessNodeIpcServer = await nodeIPCServe(environmentService.mainIPCHandle); + mainProcessNodeIpcServer = await nodeIPCServe(environmentMainService.mainIPCHandle); once(lifecycleMainService.onWillShutdown)(() => mainProcessNodeIpcServer.dispose()); } catch (error) { @@ -235,7 +235,7 @@ class CodeMain { if (error.code !== 'EADDRINUSE') { // Show a dialog for errors that can be resolved by the user - this.handleStartupDataDirError(environmentService, error); + this.handleStartupDataDirError(environmentMainService, error); // Any other runtime error is just printed to the console throw error; @@ -244,7 +244,7 @@ class CodeMain { // there's a running instance, let's connect to it let client: NodeIPCClient; try { - client = await nodeIPCConnect(environmentService.mainIPCHandle, 'main'); + client = await nodeIPCConnect(environmentMainService.mainIPCHandle, 'main'); } catch (error) { // Handle unexpected connection errors by showing a dialog to the user @@ -263,18 +263,18 @@ class CodeMain { // let's delete it, since we can't connect to it and then // retry the whole thing try { - unlinkSync(environmentService.mainIPCHandle); + unlinkSync(environmentMainService.mainIPCHandle); } catch (error) { logService.warn('Could not delete obsolete instance handle', error); throw error; } - return this.doStartup(args, logService, environmentService, lifecycleMainService, instantiationService, false); + return this.doStartup(args, logService, environmentMainService, lifecycleMainService, instantiationService, false); } // Tests from CLI require to be the only instance currently - if (environmentService.extensionTestsLocationURI && !environmentService.debugExtensionHost.break) { + if (environmentMainService.extensionTestsLocationURI && !environmentMainService.debugExtensionHost.break) { const msg = 'Running extension tests from the command line is currently only supported if no other instance of Code is running.'; logService.error(msg); client.dispose(); @@ -344,9 +344,9 @@ class CodeMain { return mainProcessNodeIpcServer; } - private handleStartupDataDirError(environmentService: IEnvironmentMainService, error: NodeJS.ErrnoException): void { + private handleStartupDataDirError(environmentMainService: IEnvironmentMainService, error: NodeJS.ErrnoException): void { if (error.code === 'EACCES' || error.code === 'EPERM') { - const directories = coalesce([environmentService.userDataPath, environmentService.extensionsPath, XDG_RUNTIME_DIR]).map(folder => getPathLabel(folder, environmentService)); + const directories = coalesce([environmentMainService.userDataPath, environmentMainService.extensionsPath, XDG_RUNTIME_DIR]).map(folder => getPathLabel(folder, environmentMainService)); this.showStartupWarningDialog( localize('startupDataDirError', "Unable to write program user data."), @@ -369,9 +369,9 @@ class CodeMain { }); } - private async windowsAllowSetForegroundWindow(launchService: ILaunchMainService, logService: ILogService): Promise { + private async windowsAllowSetForegroundWindow(launchMainService: ILaunchMainService, logService: ILogService): Promise { if (isWindows) { - const processId = await launchService.getMainProcessId(); + const processId = await launchMainService.getMainProcessId(); logService.trace('Sending some foreground love to the running instance:', processId); diff --git a/src/vs/platform/backup/electron-main/backupMainService.ts b/src/vs/platform/backup/electron-main/backupMainService.ts index ac5e6cd2eb1..ac5bb248927 100644 --- a/src/vs/platform/backup/electron-main/backupMainService.ts +++ b/src/vs/platform/backup/electron-main/backupMainService.ts @@ -38,12 +38,12 @@ export class BackupMainService implements IBackupMainService { private readonly backupPathComparer = { isEqual: (pathA: string, pathB: string) => isEqual(pathA, pathB, !isLinux) }; constructor( - @IEnvironmentMainService environmentService: IEnvironmentMainService, + @IEnvironmentMainService environmentMainService: IEnvironmentMainService, @IConfigurationService private readonly configurationService: IConfigurationService, @ILogService private readonly logService: ILogService ) { - this.backupHome = environmentService.backupHome; - this.workspacesJsonPath = environmentService.backupWorkspacesPath; + this.backupHome = environmentMainService.backupHome; + this.workspacesJsonPath = environmentMainService.backupWorkspacesPath; } async initialize(): Promise { diff --git a/src/vs/platform/driver/electron-main/driver.ts b/src/vs/platform/driver/electron-main/driver.ts index 62d7cb313e6..d4501169882 100644 --- a/src/vs/platform/driver/electron-main/driver.ts +++ b/src/vs/platform/driver/electron-main/driver.ts @@ -207,10 +207,10 @@ export class Driver implements IDriver, IWindowDriverRegistry { export async function serve( windowServer: IPCServer, handle: string, - environmentService: IEnvironmentMainService, + environmentMainService: IEnvironmentMainService, instantiationService: IInstantiationService ): Promise { - const verbose = environmentService.driverVerbose; + const verbose = environmentMainService.driverVerbose; const driver = instantiationService.createInstance(Driver, windowServer, { verbose }); const windowDriverRegistryChannel = new WindowDriverRegistryChannel(driver); diff --git a/src/vs/platform/issue/electron-main/issueMainService.ts b/src/vs/platform/issue/electron-main/issueMainService.ts index f6efb42c42d..f79bb21926c 100644 --- a/src/vs/platform/issue/electron-main/issueMainService.ts +++ b/src/vs/platform/issue/electron-main/issueMainService.ts @@ -38,7 +38,7 @@ export class IssueMainService implements ICommonIssueService { constructor( private machineId: string, private userEnv: IProcessEnvironment, - @IEnvironmentMainService private readonly environmentService: IEnvironmentMainService, + @IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService, @ILaunchMainService private readonly launchMainService: ILaunchMainService, @ILogService private readonly logService: ILogService, @IDiagnosticsService private readonly diagnosticsService: IDiagnosticsService, @@ -271,7 +271,7 @@ export class IssueMainService implements ICommonIssueService { this._processExplorerWindow.setMenuBarVisibility(false); const windowConfiguration = { - appRoot: this.environmentService.appRoot, + appRoot: this.environmentMainService.appRoot, windowId: this._processExplorerWindow.id, userEnv: this.userEnv, machineId: this.machineId, @@ -397,13 +397,13 @@ export class IssueMainService implements ICommonIssueService { } const windowConfiguration = { - appRoot: this.environmentService.appRoot, + appRoot: this.environmentMainService.appRoot, windowId: this._issueWindow.id, machineId: this.machineId, userEnv: this.userEnv, data, features, - disableExtensions: this.environmentService.disableExtensions, + disableExtensions: this.environmentMainService.disableExtensions, os: { type: os.type(), arch: os.arch(), diff --git a/src/vs/platform/menubar/electron-main/menubar.ts b/src/vs/platform/menubar/electron-main/menubar.ts index 076f39011cb..87c5b80744b 100644 --- a/src/vs/platform/menubar/electron-main/menubar.ts +++ b/src/vs/platform/menubar/electron-main/menubar.ts @@ -67,7 +67,7 @@ export class Menubar { @IUpdateService private readonly updateService: IUpdateService, @IConfigurationService private readonly configurationService: IConfigurationService, @IWindowsMainService private readonly windowsMainService: IWindowsMainService, - @IEnvironmentMainService private readonly environmentService: IEnvironmentMainService, + @IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IWorkspacesHistoryMainService private readonly workspacesHistoryMainService: IWorkspacesHistoryMainService, @IStateService private readonly stateService: IStateService, @@ -499,7 +499,7 @@ export class Menubar { const openInNewWindow = this.isOptionClick(event); const success = this.windowsMainService.open({ context: OpenContext.MENU, - cli: this.environmentService.args, + cli: this.environmentMainService.args, urisToOpen: [openable], forceNewWindow: openInNewWindow, gotoLineMode: false @@ -716,7 +716,7 @@ export class Menubar { if (activeWindow) { this.logService.trace('menubar#runActionInRenderer', invocation); - if (isMacintosh && !this.environmentService.isBuilt && !activeWindow.isReady) { + if (isMacintosh && !this.environmentMainService.isBuilt && !activeWindow.isReady) { if ((invocation.type === 'commandId' && invocation.commandId === 'workbench.action.toggleDevTools') || (invocation.type !== 'commandId' && invocation.userSettingsLabel === 'alt+cmd+i')) { // prevent this action from running twice on macOS (https://github.com/microsoft/vscode/issues/62719) // we already register a keybinding in bootstrap-window.js for opening developer tools in case something diff --git a/src/vs/platform/native/electron-main/nativeHostMainService.ts b/src/vs/platform/native/electron-main/nativeHostMainService.ts index 918ca38c2cb..929af851987 100644 --- a/src/vs/platform/native/electron-main/nativeHostMainService.ts +++ b/src/vs/platform/native/electron-main/nativeHostMainService.ts @@ -47,7 +47,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain @IWindowsMainService private readonly windowsMainService: IWindowsMainService, @IDialogMainService private readonly dialogMainService: IDialogMainService, @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, - @IEnvironmentMainService private readonly environmentService: IEnvironmentMainService, + @IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService, @ITelemetryService private readonly telemetryService: ITelemetryService, @ILogService private readonly logService: ILogService ) { @@ -140,7 +140,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain context: OpenContext.API, contextWindowId: windowId, urisToOpen: toOpen, - cli: this.environmentService.args, + cli: this.environmentMainService.args, forceNewWindow: options.forceNewWindow, forceReuseWindow: options.forceReuseWindow, preferNewWindow: options.preferNewWindow, @@ -293,7 +293,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain this.windowsMainService.open({ context: OpenContext.DIALOG, contextWindowId: windowId, - cli: this.environmentService.args, + cli: this.environmentMainService.args, urisToOpen: openable, forceNewWindow: options.forceNewWindow }); @@ -386,7 +386,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain const promptOptions = { name: product.nameLong.replace('-', ''), - icns: (isMacintosh && this.environmentService.isBuilt) ? join(dirname(this.environmentService.appRoot), `${product.nameShort}.icns`) : undefined + icns: (isMacintosh && this.environmentMainService.isBuilt) ? join(dirname(this.environmentMainService.appRoot), `${product.nameShort}.icns`) : undefined }; sudoPrompt.exec(sudoCommand.join(' '), promptOptions, (error: string, stdout: string, stderr: string) => { @@ -412,28 +412,28 @@ export class NativeHostMainService extends Disposable implements INativeHostMain // Windows if (isWindows) { - if (this.environmentService.isBuilt) { + if (this.environmentMainService.isBuilt) { return join(dirname(process.execPath), 'bin', `${product.applicationName}.cmd`); } - return join(this.environmentService.appRoot, 'scripts', 'code-cli.bat'); + return join(this.environmentMainService.appRoot, 'scripts', 'code-cli.bat'); } // Linux if (isLinux) { - if (this.environmentService.isBuilt) { + if (this.environmentMainService.isBuilt) { return join(dirname(process.execPath), 'bin', `${product.applicationName}`); } - return join(this.environmentService.appRoot, 'scripts', 'code-cli.sh'); + return join(this.environmentMainService.appRoot, 'scripts', 'code-cli.sh'); } // macOS - if (this.environmentService.isBuilt) { - return join(this.environmentService.appRoot, 'bin', 'code'); + if (this.environmentMainService.isBuilt) { + return join(this.environmentMainService.appRoot, 'bin', 'code'); } - return join(this.environmentService.appRoot, 'scripts', 'code-cli.sh'); + return join(this.environmentMainService.appRoot, 'scripts', 'code-cli.sh'); } async getOSStatistics(): Promise { @@ -505,7 +505,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain //#region macOS Touchbar async newWindowTab(): Promise { - this.windowsMainService.open({ context: OpenContext.API, cli: this.environmentService.args, forceNewTabbedWindow: true, forceEmpty: true }); + this.windowsMainService.open({ context: OpenContext.API, cli: this.environmentMainService.args, forceNewTabbedWindow: true, forceEmpty: true }); } async showPreviousWindowTab(): Promise { diff --git a/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts b/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts index c0aad5ffa10..966a8830bf6 100644 --- a/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts +++ b/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts @@ -26,7 +26,7 @@ export class SharedProcess extends Disposable implements ISharedProcess { constructor( private readonly machineId: string, private userEnv: NodeJS.ProcessEnv, - @IEnvironmentMainService private readonly environmentService: IEnvironmentMainService, + @IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService, @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, @ILogService private readonly logService: ILogService, @IThemeMainService private readonly themeMainService: IThemeMainService @@ -164,11 +164,11 @@ export class SharedProcess extends Disposable implements ISharedProcess { const config: ISharedProcessConfiguration = { machineId: this.machineId, windowId: this.window.id, - appRoot: this.environmentService.appRoot, - nodeCachedDataDir: this.environmentService.nodeCachedDataDir, - backupWorkspacesPath: this.environmentService.backupWorkspacesPath, + appRoot: this.environmentMainService.appRoot, + nodeCachedDataDir: this.environmentMainService.nodeCachedDataDir, + backupWorkspacesPath: this.environmentMainService.backupWorkspacesPath, userEnv: this.userEnv, - args: this.environmentService.args, + args: this.environmentMainService.args, logLevel: this.logService.getLevel() }; diff --git a/src/vs/platform/update/electron-main/abstractUpdateService.ts b/src/vs/platform/update/electron-main/abstractUpdateService.ts index f15dec1b8a7..2d96ce768ad 100644 --- a/src/vs/platform/update/electron-main/abstractUpdateService.ts +++ b/src/vs/platform/update/electron-main/abstractUpdateService.ts @@ -46,7 +46,7 @@ export abstract class AbstractUpdateService implements IUpdateService { constructor( @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, @IConfigurationService protected configurationService: IConfigurationService, - @IEnvironmentMainService private readonly environmentService: IEnvironmentMainService, + @IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService, @IRequestService protected requestService: IRequestService, @ILogService protected logService: ILogService, ) { } @@ -57,11 +57,11 @@ export abstract class AbstractUpdateService implements IUpdateService { * https://github.com/microsoft/vscode/issues/89784 */ initialize(): void { - if (!this.environmentService.isBuilt) { + if (!this.environmentMainService.isBuilt) { return; // updates are never enabled when running out of sources } - if (this.environmentService.disableUpdates) { + if (this.environmentMainService.disableUpdates) { this.logService.info('update#ctor - updates are disabled by the environment'); return; } diff --git a/src/vs/platform/update/electron-main/updateService.darwin.ts b/src/vs/platform/update/electron-main/updateService.darwin.ts index ddfa1ee4a5f..8d67a459903 100644 --- a/src/vs/platform/update/electron-main/updateService.darwin.ts +++ b/src/vs/platform/update/electron-main/updateService.darwin.ts @@ -32,11 +32,11 @@ export class DarwinUpdateService extends AbstractUpdateService { @ILifecycleMainService lifecycleMainService: ILifecycleMainService, @IConfigurationService configurationService: IConfigurationService, @ITelemetryService private readonly telemetryService: ITelemetryService, - @IEnvironmentMainService environmentService: IEnvironmentMainService, + @IEnvironmentMainService environmentMainService: IEnvironmentMainService, @IRequestService requestService: IRequestService, @ILogService logService: ILogService ) { - super(lifecycleMainService, configurationService, environmentService, requestService, logService); + super(lifecycleMainService, configurationService, environmentMainService, requestService, logService); } initialize(): void { diff --git a/src/vs/platform/update/electron-main/updateService.linux.ts b/src/vs/platform/update/electron-main/updateService.linux.ts index 91565b13954..d00055b590f 100644 --- a/src/vs/platform/update/electron-main/updateService.linux.ts +++ b/src/vs/platform/update/electron-main/updateService.linux.ts @@ -23,12 +23,12 @@ export class LinuxUpdateService extends AbstractUpdateService { @ILifecycleMainService lifecycleMainService: ILifecycleMainService, @IConfigurationService configurationService: IConfigurationService, @ITelemetryService private readonly telemetryService: ITelemetryService, - @IEnvironmentMainService environmentService: IEnvironmentMainService, + @IEnvironmentMainService environmentMainService: IEnvironmentMainService, @IRequestService requestService: IRequestService, @ILogService logService: ILogService, @INativeHostMainService private readonly nativeHostMainService: INativeHostMainService ) { - super(lifecycleMainService, configurationService, environmentService, requestService, logService); + super(lifecycleMainService, configurationService, environmentMainService, requestService, logService); } protected buildUpdateFeedUrl(quality: string): string { diff --git a/src/vs/platform/update/electron-main/updateService.snap.ts b/src/vs/platform/update/electron-main/updateService.snap.ts index 1712182c365..e0d6010d06a 100644 --- a/src/vs/platform/update/electron-main/updateService.snap.ts +++ b/src/vs/platform/update/electron-main/updateService.snap.ts @@ -36,10 +36,10 @@ abstract class AbstractUpdateService2 implements IUpdateService { constructor( @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, - @IEnvironmentMainService environmentService: IEnvironmentMainService, + @IEnvironmentMainService environmentMainService: IEnvironmentMainService, @ILogService protected logService: ILogService, ) { - if (environmentService.disableUpdates) { + if (environmentMainService.disableUpdates) { this.logService.info('update#ctor - updates are disabled'); return; } @@ -140,11 +140,11 @@ export class SnapUpdateService extends AbstractUpdateService2 { private snap: string, private snapRevision: string, @ILifecycleMainService lifecycleMainService: ILifecycleMainService, - @IEnvironmentMainService environmentService: IEnvironmentMainService, + @IEnvironmentMainService environmentMainService: IEnvironmentMainService, @ILogService logService: ILogService, @ITelemetryService private readonly telemetryService: ITelemetryService ) { - super(lifecycleMainService, environmentService, logService); + super(lifecycleMainService, environmentMainService, logService); const watcher = watch(path.dirname(this.snap)); const onChange = Event.fromNodeEventEmitter(watcher, 'change', (_, fileName: string) => fileName); diff --git a/src/vs/platform/update/electron-main/updateService.win32.ts b/src/vs/platform/update/electron-main/updateService.win32.ts index c92a0931dcc..3fcc37e91d4 100644 --- a/src/vs/platform/update/electron-main/updateService.win32.ts +++ b/src/vs/platform/update/electron-main/updateService.win32.ts @@ -63,13 +63,13 @@ export class Win32UpdateService extends AbstractUpdateService { @ILifecycleMainService lifecycleMainService: ILifecycleMainService, @IConfigurationService configurationService: IConfigurationService, @ITelemetryService private readonly telemetryService: ITelemetryService, - @IEnvironmentMainService environmentService: IEnvironmentMainService, + @IEnvironmentMainService environmentMainService: IEnvironmentMainService, @IRequestService requestService: IRequestService, @ILogService logService: ILogService, @IFileService private readonly fileService: IFileService, @INativeHostMainService private readonly nativeHostMainService: INativeHostMainService ) { - super(lifecycleMainService, configurationService, environmentService, requestService, logService); + super(lifecycleMainService, configurationService, environmentMainService, requestService, logService); } initialize(): void { diff --git a/src/vs/platform/url/electron-main/electronUrlListener.ts b/src/vs/platform/url/electron-main/electronUrlListener.ts index 9ae6d13d2af..e281cff7d5e 100644 --- a/src/vs/platform/url/electron-main/electronUrlListener.ts +++ b/src/vs/platform/url/electron-main/electronUrlListener.ts @@ -43,7 +43,7 @@ export class ElectronURLListener { initialUrisToHandle: { uri: URI, url: string }[], private readonly urlService: IURLService, windowsMainService: IWindowsMainService, - environmentService: IEnvironmentMainService + environmentMainService: IEnvironmentMainService ) { // the initial set of URIs we need to handle once the window is ready @@ -51,7 +51,7 @@ export class ElectronURLListener { // Windows: install as protocol handler if (isWindows) { - const windowsParameters = environmentService.isBuilt ? [] : [`"${environmentService.appRoot}"`]; + const windowsParameters = environmentMainService.isBuilt ? [] : [`"${environmentMainService.appRoot}"`]; windowsParameters.push('--open-url', '--'); app.setAsDefaultProtocolClient(product.urlProtocol, process.execPath, windowsParameters); } diff --git a/src/vs/platform/windows/electron-main/windowsMainService.ts b/src/vs/platform/windows/electron-main/windowsMainService.ts index c1244908aa5..db2b237d45e 100644 --- a/src/vs/platform/windows/electron-main/windowsMainService.ts +++ b/src/vs/platform/windows/electron-main/windowsMainService.ts @@ -137,7 +137,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic private readonly initialUserEnv: IProcessEnvironment, @ILogService private readonly logService: ILogService, @IStateService private readonly stateService: IStateService, - @IEnvironmentMainService private readonly environmentService: IEnvironmentMainService, + @IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService, @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, @IBackupMainService private readonly backupMainService: IBackupMainService, @IConfigurationService private readonly configurationService: IConfigurationService, @@ -159,7 +159,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic } openEmptyWindow(openConfig: IOpenEmptyConfiguration, options?: IOpenEmptyWindowOptions): ICodeWindow[] { - let cli = this.environmentService.args; + let cli = this.environmentMainService.args; const remote = options?.remoteAuthority; if (cli && (cli.remote !== remote)) { cli = { ...cli, remote }; @@ -670,7 +670,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic buttons: [localize('ok', "OK")], message: uri.scheme === Schemas.file ? localize('pathNotExistTitle', "Path does not exist") : localize('uriInvalidTitle', "URI can not be opened"), detail: uri.scheme === Schemas.file ? - localize('pathNotExistDetail', "The path '{0}' does not seem to exist anymore on disk.", getPathLabel(uri.fsPath, this.environmentService)) : + localize('pathNotExistDetail', "The path '{0}' does not seem to exist anymore on disk.", getPathLabel(uri.fsPath, this.environmentMainService)) : localize('uriInvalidDetail', "The URI '{0}' is not valid and can not be opened.", uri.toString()), noLink: true }; @@ -1135,9 +1135,9 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic // Build `INativeWindowConfiguration` from config and options const configuration = { ...options.cli } as INativeWindowConfiguration; - configuration.appRoot = this.environmentService.appRoot; + configuration.appRoot = this.environmentMainService.appRoot; configuration.machineId = this.machineId; - configuration.nodeCachedDataDir = this.environmentService.nodeCachedDataDir; + configuration.nodeCachedDataDir = this.environmentMainService.nodeCachedDataDir; configuration.mainPid = process.pid; configuration.execPath = process.execPath; configuration.userEnv = { ...this.initialUserEnv, ...options.userEnv }; @@ -1157,7 +1157,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic // For all other cases we first call into registerEmptyWindowBackupSync() to set it before // loading the window. if (options.emptyWindowBackupInfo) { - configuration.backupPath = join(this.environmentService.backupHome, options.emptyWindowBackupInfo.backupFolder); + configuration.backupPath = join(this.environmentMainService.backupHome, options.emptyWindowBackupInfo.backupFolder); } let window: ICodeWindow | undefined; diff --git a/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts index 30b358c4ce8..22cec5f95ad 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts @@ -66,7 +66,7 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa @IStateService private readonly stateService: IStateService, @ILogService private readonly logService: ILogService, @IWorkspacesManagementMainService private readonly workspacesManagementMainService: IWorkspacesManagementMainService, - @IEnvironmentMainService private readonly environmentService: IEnvironmentMainService, + @IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService, @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService ) { super(); @@ -402,7 +402,7 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa } // Workspace: Untitled - if (extUriBiasedIgnorePathCase.isEqualOrParent(workspace.configPath, this.environmentService.userHome)) { + if (extUriBiasedIgnorePathCase.isEqualOrParent(workspace.configPath, this.environmentMainService.userHome)) { return { title: localize('untitledWorkspace', "Untitled (Workspace)"), description: '' }; } diff --git a/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts index d738633f973..cb397ad60e8 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts @@ -65,7 +65,7 @@ export class WorkspacesManagementMainService extends Disposable implements IWork declare readonly _serviceBrand: undefined; - private readonly untitledWorkspacesHome = this.environmentService.untitledWorkspacesHome; // local URI that contains all untitled workspaces + private readonly untitledWorkspacesHome = this.environmentMainService.untitledWorkspacesHome; // local URI that contains all untitled workspaces private readonly _onDidDeleteUntitledWorkspace = this._register(new Emitter()); readonly onDidDeleteUntitledWorkspace: Event = this._onDidDeleteUntitledWorkspace.event; @@ -74,7 +74,7 @@ export class WorkspacesManagementMainService extends Disposable implements IWork readonly onDidEnterWorkspace: Event = this._onDidEnterWorkspace.event; constructor( - @IEnvironmentMainService private readonly environmentService: IEnvironmentMainService, + @IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService, @ILogService private readonly logService: ILogService, @IBackupMainService private readonly backupMainService: IBackupMainService, @IDialogMainService private readonly dialogMainService: IDialogMainService @@ -101,7 +101,7 @@ export class WorkspacesManagementMainService extends Disposable implements IWork } private isWorkspacePath(uri: URI): boolean { - return isUntitledWorkspace(uri, this.environmentService) || hasWorkspaceFileExtension(uri); + return isUntitledWorkspace(uri, this.environmentMainService) || hasWorkspaceFileExtension(uri); } private doResolveWorkspace(path: URI, contents: string): IResolvedWorkspace | null { @@ -186,7 +186,7 @@ export class WorkspacesManagementMainService extends Disposable implements IWork } isUntitledWorkspace(workspace: IWorkspaceIdentifier): boolean { - return isUntitledWorkspace(workspace.configPath, this.environmentService); + return isUntitledWorkspace(workspace.configPath, this.environmentMainService); } deleteUntitledWorkspaceSync(workspace: IWorkspaceIdentifier): void { @@ -213,7 +213,7 @@ export class WorkspacesManagementMainService extends Disposable implements IWork rimrafSync(dirname(configPath)); // Mark Workspace Storage to be deleted - const workspaceStoragePath = join(this.environmentService.workspaceStorageHome.fsPath, workspace.id); + const workspaceStoragePath = join(this.environmentMainService.workspaceStorageHome.fsPath, workspace.id); if (existsSync(workspaceStoragePath)) { writeFileSync(join(workspaceStoragePath, 'obsolete'), ''); } diff --git a/src/vs/platform/workspaces/test/electron-main/workspacesManagementMainService.test.ts b/src/vs/platform/workspaces/test/electron-main/workspacesManagementMainService.test.ts index fc4b803c38a..55ad732b8b3 100644 --- a/src/vs/platform/workspaces/test/electron-main/workspacesManagementMainService.test.ts +++ b/src/vs/platform/workspaces/test/electron-main/workspacesManagementMainService.test.ts @@ -81,14 +81,14 @@ suite('WorkspacesManagementMainService', () => { let testDir: string; let untitledWorkspacesHomePath: string; - let environmentService: EnvironmentMainService; + let environmentMainService: EnvironmentMainService; let service: WorkspacesManagementMainService; setup(async () => { testDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'workspacesmanagementmainservice'); untitledWorkspacesHomePath = path.join(testDir, 'Workspaces'); - environmentService = new class TestEnvironmentService extends EnvironmentMainService { + environmentMainService = new class TestEnvironmentService extends EnvironmentMainService { constructor() { super(parseArgs(process.argv, OPTIONS)); } @@ -97,7 +97,7 @@ suite('WorkspacesManagementMainService', () => { } }; - service = new WorkspacesManagementMainService(environmentService, new NullLogService(), new TestBackupMainService(), new TestDialogMainService()); + service = new WorkspacesManagementMainService(environmentMainService, new NullLogService(), new TestBackupMainService(), new TestDialogMainService()); return fs.promises.mkdir(untitledWorkspacesHomePath, { recursive: true }); }); From 72137a822335573fc47950d7cfd451374c309e52 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 16 Feb 2021 09:10:55 +0100 Subject: [PATCH 179/325] fixes #116663 --- src/vs/workbench/contrib/debug/browser/breakpointsView.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/breakpointsView.ts b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts index a257c4d65bb..eca16433e3b 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointsView.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts @@ -688,9 +688,7 @@ class FunctionBreakpointInputRenderer implements IListRenderer { // Need to react with a timeout on the blur event due to possible concurent splices #56443 setTimeout(() => { - if (!template.breakpoint.name) { - wrapUp(true); - } + wrapUp(!!inputBox.value); }); })); From 55393229982b2ef32d68b766fc69f06585be596b Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 16 Feb 2021 09:20:44 +0100 Subject: [PATCH 180/325] "e; is ", re #115391 --- src/vs/base/browser/markdownRenderer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/base/browser/markdownRenderer.ts b/src/vs/base/browser/markdownRenderer.ts index 2feb2ab7f0c..5378627e57a 100644 --- a/src/vs/base/browser/markdownRenderer.ts +++ b/src/vs/base/browser/markdownRenderer.ts @@ -385,7 +385,7 @@ export function renderMarkdownAsPlaintext(markdown: IMarkdownString) { } const unescapeInfo = new Map([ - ['"', ':'], + ['"', '"'], ['&', '&'], [''', '\''], ['<', '<'], From 5662aecf24197fe1343c471932bf07a460e7a0ec Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 16 Feb 2021 09:28:13 +0100 Subject: [PATCH 181/325] actionBar: adopt respectOrienationForPreviousAndNextKey option in lists and notebook --- src/vs/base/browser/ui/actionbar/actionbar.ts | 5 +++-- src/vs/base/browser/ui/toolbar/toolbar.ts | 2 ++ src/vs/workbench/browser/parts/views/treeView.ts | 3 ++- .../workbench/contrib/debug/browser/breakpointsView.ts | 6 +++--- src/vs/workbench/contrib/debug/browser/callStackView.ts | 7 ++++--- .../contrib/extensions/browser/extensionsList.ts | 3 ++- .../contrib/files/browser/views/openEditorsView.ts | 4 ++-- .../contrib/markers/browser/markersTreeViewer.ts | 3 ++- .../contrib/notebook/browser/diff/diffComponents.ts | 3 ++- .../notebook/browser/diff/notebookTextDiffList.ts | 3 ++- .../notebook/browser/view/renderers/cellRenderer.ts | 9 ++++++--- .../contrib/preferences/browser/settingsTree.ts | 1 + .../contrib/preferences/browser/settingsWidgets.ts | 2 +- src/vs/workbench/contrib/remote/browser/tunnelView.ts | 3 ++- .../contrib/scm/browser/scmRepositoryRenderer.ts | 2 +- src/vs/workbench/contrib/scm/browser/scmViewPane.ts | 5 +++-- .../contrib/search/browser/searchResultsView.ts | 6 +++--- .../contrib/testing/browser/testingExplorerView.ts | 3 ++- 18 files changed, 43 insertions(+), 27 deletions(-) diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index 8a912e1255c..83135785546 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -35,6 +35,7 @@ export interface IActionBarOptions { readonly triggerKeys?: ActionTrigger; readonly allowContextMenu?: boolean; readonly preventLoopNavigation?: boolean; + // Pass true here when the up and down keys should not be eaten up by the ActionBar. For example, when an ActionBar is in the list. readonly respectOrientationForPreviousAndNextKey?: boolean; } @@ -145,9 +146,9 @@ export class ActionBar extends Disposable implements IActionRunner { const focusedItem = typeof this.focusedItem === 'number' ? this.viewItems[this.focusedItem] : undefined; if (previousKeys && (event.equals(previousKeys[0]) || event.equals(previousKeys[1]))) { - eventHandled = this.focusPrevious() && this.viewItems.length > 1; + eventHandled = this.focusPrevious(); } else if (nextKeys && (event.equals(nextKeys[0]) || event.equals(nextKeys[1]))) { - eventHandled = this.focusNext() && this.viewItems.length > 1; + eventHandled = this.focusNext(); } else if (event.equals(KeyCode.Escape) && this.cancelHasListener) { this._onDidCancel.fire(); } else if (event.equals(KeyCode.Tab) && focusedItem instanceof BaseActionViewItem && focusedItem.trapsArrowNavigation) { diff --git a/src/vs/base/browser/ui/toolbar/toolbar.ts b/src/vs/base/browser/ui/toolbar/toolbar.ts index c1348a93ddc..3b91ffa5573 100644 --- a/src/vs/base/browser/ui/toolbar/toolbar.ts +++ b/src/vs/base/browser/ui/toolbar/toolbar.ts @@ -28,6 +28,7 @@ export interface IToolBarOptions { anchorAlignmentProvider?: () => AnchorAlignment; renderDropdownAsChildElement?: boolean; moreIcon?: CSSIcon; + readonly respectOrientationForPreviousAndNextKey?: boolean; } /** @@ -63,6 +64,7 @@ export class ToolBar extends Disposable { orientation: options.orientation, ariaLabel: options.ariaLabel, actionRunner: options.actionRunner, + respectOrientationForPreviousAndNextKey: options.respectOrientationForPreviousAndNextKey, actionViewItemProvider: (action: IAction) => { if (action.id === ToggleMenuAction.ID) { this.toggleMenuActionViewItem = new DropdownMenuActionViewItem( diff --git a/src/vs/workbench/browser/parts/views/treeView.ts b/src/vs/workbench/browser/parts/views/treeView.ts index 9c49ffdcca2..f8961757153 100644 --- a/src/vs/workbench/browser/parts/views/treeView.ts +++ b/src/vs/workbench/browser/parts/views/treeView.ts @@ -873,7 +873,8 @@ class TreeRenderer extends Disposable implements ITreeRenderer { return action.createActionViewItem(); } return new ExtensionActionViewItem(null, action, actionOptions); - } + }, + respectOrientationForPreviousAndNextKey: true }); actionbar.onDidRun(({ error }) => error && this.notificationService.error(error)); diff --git a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts index e54534fd378..9936ef5a754 100644 --- a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts @@ -537,7 +537,7 @@ class EditorGroupRenderer implements IListRenderer action.id === QuickFixAction.ID ? _instantiationService.createInstance(QuickFixActionViewItem, action) : undefined + actionViewItemProvider: (action: IAction) => action.id === QuickFixAction.ID ? _instantiationService.createInstance(QuickFixActionViewItem, action) : undefined, + respectOrientationForPreviousAndNextKey: true })); this.icon = dom.append(parent, dom.$('')); this.multilineActionbar = this._register(new ActionBar(dom.append(parent, dom.$('.multiline-actions')), { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 235dd429996..24f880fbabf 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -150,7 +150,8 @@ class PropertyHeader extends Disposable { } return undefined; - } + }, + respectOrientationForPreviousAndNextKey: true }); this._register(this._toolbar); this._toolbar.context = { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts index ce2bc9c6ec2..e25db2f37b0 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts @@ -188,7 +188,8 @@ export class CellDiffSideBySideRenderer implements IListRenderer extends Dispo rowElement.setAttribute('tabindex', item.selected ? '0' : '-1'); rowElement.classList.toggle('selected', item.selected); - const actionBar = new ActionBar(rowElement); + const actionBar = new ActionBar(rowElement, { respectOrientationForPreviousAndNextKey: true }); this.listDisposables.add(actionBar); actionBar.push(this.getActionsForItem(item, idx), { icon: true, label: true }); diff --git a/src/vs/workbench/contrib/remote/browser/tunnelView.ts b/src/vs/workbench/contrib/remote/browser/tunnelView.ts index daa3fba23f9..02b75df99e9 100644 --- a/src/vs/workbench/contrib/remote/browser/tunnelView.ts +++ b/src/vs/workbench/contrib/remote/browser/tunnelView.ts @@ -225,7 +225,8 @@ class TunnelTreeRenderer extends Disposable implements ITreeRenderer action instanceof MenuItemAction ? this.instantiationService.createInstance(MenuEntryActionViewItem, action) - : undefined + : undefined, + respectOrientationForPreviousAndNextKey: true }); return { label, actionBar, icon }; From ac916cbb2dfeabf39aaec1feb196f0ed23b236f6 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 16 Feb 2021 09:32:26 +0100 Subject: [PATCH 182/325] don't assert rpc strictness yet --- .../src/singlefolder-tests/notebook.document.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts index 3a2c081f1d5..34a8218e3a1 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts @@ -33,7 +33,7 @@ suite('Notebook Document', function () { const disposables: vscode.Disposable[] = []; suiteTeardown(async function () { - utils.assertNoRpc(); + // utils.assertNoRpc(); await utils.revertAllDirty(); await utils.closeAllEditors(); utils.disposeAll(disposables); From f829a7dfd7eae502eb020fbb7f636b7a3017a654 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 16 Feb 2021 09:45:37 +0100 Subject: [PATCH 183/325] workaround for https://github.com/microsoft/vscode/issues/116751 --- src/vs/workbench/api/common/extHostTypes.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index e7cd5a11828..9bc85fa2ace 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -2863,12 +2863,13 @@ export class NotebookCellRange { } constructor(start: number, end: number) { - if (start < 0) { - throw illegalArgument('start must be positive'); - } - if (end < start) { - throw illegalArgument('end cannot be smaller than start'); - } + // todo@rebornix + // if (start < 0) { + // throw illegalArgument('start must be positive'); + // } + // if (end < start) { + // throw illegalArgument('end cannot be smaller than start'); + // } this._start = start; this._end = end; } From a7470e5094bb8c8d11893643535eebd6676a4d9e Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 16 Feb 2021 09:55:35 +0100 Subject: [PATCH 184/325] storage - let service own lifecycle in main and implement storage warming when window loads --- src/vs/base/parts/storage/common/storage.ts | 11 +++- .../electron-main/lifecycleMainService.ts | 53 ++++++++++++++----- .../storage/electron-main/storageMain.ts | 31 +++-------- .../electron-main/storageMainService.ts | 52 ++++++++++++++++-- .../electron-main/storageMainService.test.ts | 13 +++-- .../platform/windows/electron-main/window.ts | 10 ++-- .../platform/windows/electron-main/windows.ts | 6 ++- .../electron-main/windowsMainService.ts | 4 +- .../electron-main/windowsStateHandler.ts | 42 +++++++-------- .../{window.test.ts => windowsFinder.test.ts} | 4 +- 10 files changed, 145 insertions(+), 81 deletions(-) rename src/vs/platform/windows/test/electron-main/{window.test.ts => windowsFinder.test.ts} (97%) diff --git a/src/vs/base/parts/storage/common/storage.ts b/src/vs/base/parts/storage/common/storage.ts index c2f5ff5a5cd..66023e7d651 100644 --- a/src/vs/base/parts/storage/common/storage.ts +++ b/src/vs/base/parts/storage/common/storage.ts @@ -89,6 +89,8 @@ export class Storage extends Disposable implements IStorage { private pendingDeletes = new Set(); private pendingInserts = new Map(); + private pendingClose: Promise | undefined = undefined; + private readonly whenFlushedCallbacks: Function[] = []; constructor( @@ -256,10 +258,15 @@ export class Storage extends Disposable implements IStorage { } async close(): Promise { - if (this.state === StorageState.Closed) { - return; // return if already closed + if (!this.pendingClose) { + this.pendingClose = this.doClose(); } + return this.pendingClose; + } + + private async doClose(): Promise { + // Update state this.state = StorageState.Closed; diff --git a/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts b/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts index 29a7082b742..6d9a34dba09 100644 --- a/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts +++ b/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts @@ -11,9 +11,10 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import { ICodeWindow } from 'vs/platform/windows/electron-main/windows'; import { handleVetos } from 'vs/platform/lifecycle/common/lifecycle'; import { isMacintosh, isWindows } from 'vs/base/common/platform'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { Promises, Barrier, timeout } from 'vs/base/common/async'; import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; +import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; export const ILifecycleMainService = createDecorator('lifecycleMainService'); @@ -24,6 +25,11 @@ export const enum UnloadReason { LOAD = 4 } +export interface IWindowLoadEvent { + window: ICodeWindow; + workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined; +} + export interface IWindowUnloadEvent { window: ICodeWindow; reason: UnloadReason; @@ -72,16 +78,27 @@ export interface ILifecycleMainService { readonly onWillShutdown: Event; /** - * An event that fires before a window closes. This event is fired after any veto has been dealt - * with so that listeners know for sure that the window will close without veto. + * An event that fires when a window is loading. This can either be a window opening for the + * first time or a window reloading or changing to another URL. */ - readonly onBeforeWindowClose: Event; + readonly onWillLoadWindow: Event; /** * An event that fires before a window is about to unload. Listeners can veto this event to prevent * the window from unloading. */ - readonly onBeforeWindowUnload: Event; + readonly onBeforeUnloadWindow: Event; + + /** + * An event that fires before a window closes. This event is fired after any veto has been dealt + * with so that listeners know for sure that the window will close without veto. + */ + readonly onBeforeCloseWindow: Event; + + /** + * Make a `ICodeWindow` known to the lifecycle main service. + */ + registerWindow(window: ICodeWindow): void; /** * Reload a window. All lifecycle event handlers are triggered. @@ -147,11 +164,14 @@ export class LifecycleMainService extends Disposable implements ILifecycleMainSe private readonly _onWillShutdown = this._register(new Emitter()); readonly onWillShutdown = this._onWillShutdown.event; - private readonly _onBeforeWindowClose = this._register(new Emitter()); - readonly onBeforeWindowClose = this._onBeforeWindowClose.event; + private readonly _onWillLoadWindow = this._register(new Emitter()); + readonly onWillLoadWindow = this._onWillLoadWindow.event; - private readonly _onBeforeWindowUnload = this._register(new Emitter()); - readonly onBeforeWindowUnload = this._onBeforeWindowUnload.event; + private readonly _onBeforeCloseWindow = this._register(new Emitter()); + readonly onBeforeCloseWindow = this._onBeforeCloseWindow.event; + + private readonly _onBeforeUnloadWindow = this._register(new Emitter()); + readonly onBeforeUnloadWindow = this._onBeforeUnloadWindow.event; private _quitRequested = false; get quitRequested(): boolean { return this._quitRequested; } @@ -314,10 +334,14 @@ export class LifecycleMainService extends Disposable implements ILifecycleMainSe } registerWindow(window: ICodeWindow): void { + const windowListeners = new DisposableStore(); // track window count this.windowCounter++; + // Window Will Load + windowListeners.add(window.onWillLoad(e => this._onWillLoadWindow.fire({ window, workspace: e.workspace }))); + // Window Before Closing: Main -> Renderer window.win.on('close', e => { @@ -341,9 +365,9 @@ export class LifecycleMainService extends Disposable implements ILifecycleMainSe this.windowToCloseRequest.add(windowId); - // Fire onBeforeWindowClose before actually closing - this.logService.trace(`Lifecycle#onBeforeWindowClose.fire() - window ID ${windowId}`); - this._onBeforeWindowClose.fire(window); + // Fire onBeforeCloseWindow before actually closing + this.logService.trace(`Lifecycle#onBeforeCloseWindow.fire() - window ID ${windowId}`); + this._onBeforeCloseWindow.fire(window); // No veto, close window now window.close(); @@ -357,6 +381,9 @@ export class LifecycleMainService extends Disposable implements ILifecycleMainSe // update window count this.windowCounter--; + // clear window listeners + windowListeners.dispose(); + // if there are no more code windows opened, fire the onWillShutdown event, unless // we are on macOS where it is perfectly fine to close the last window and // the application continues running (unless quit was actually requested) @@ -452,7 +479,7 @@ export class LifecycleMainService extends Disposable implements ILifecycleMainSe private onBeforeUnloadWindowInMain(window: ICodeWindow, reason: UnloadReason): Promise { const vetos: (boolean | Promise)[] = []; - this._onBeforeWindowUnload.fire({ + this._onBeforeUnloadWindow.fire({ reason, window, veto(value) { diff --git a/src/vs/platform/storage/electron-main/storageMain.ts b/src/vs/platform/storage/electron-main/storageMain.ts index 9bb316f0ef3..0b4cec2c83d 100644 --- a/src/vs/platform/storage/electron-main/storageMain.ts +++ b/src/vs/platform/storage/electron-main/storageMain.ts @@ -6,7 +6,7 @@ import { promises } from 'fs'; import { exists, writeFile } from 'vs/base/node/pfs'; import { Event, Emitter } from 'vs/base/common/event'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { ILogService, LogLevel } from 'vs/platform/log/common/log'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { SQLiteStorageDatabase, ISQLiteStorageDatabaseLoggingOptions } from 'vs/base/parts/storage/node/storage'; @@ -16,13 +16,12 @@ import { IS_NEW_KEY } from 'vs/platform/storage/common/storage'; import { currentSessionDateStorageKey, firstSessionDateStorageKey, instanceStorageKey, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry'; import { generateUuid } from 'vs/base/common/uuid'; import { IEmptyWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { ILifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; /** * Provides access to global and workspace storage from the * electron-main side that is the owner of all storage connections. */ -export interface IStorageMain { +export interface IStorageMain extends IDisposable { /** * Emitted whenever data is updated or deleted. @@ -101,25 +100,9 @@ abstract class BaseStorageMain extends Disposable implements IStorageMain { private initializePromise: Promise | undefined = undefined; constructor( - protected readonly logService: ILogService, - private readonly lifecycleMainService: ILifecycleMainService + protected readonly logService: ILogService ) { super(); - - this.registerListeners(); - } - - private registerListeners(): void { - - // Lifecycle: Warmup (in parallel to window open) - (async () => { - await this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen); - - this.initialize(); - })(); - - // Lifecycle: Shutdown - this.lifecycleMainService.onWillShutdown(e => e.join(this.close())); } initialize(): Promise { @@ -202,10 +185,9 @@ export class GlobalStorageMain extends BaseStorageMain implements IStorageMain { constructor( logService: ILogService, - private readonly environmentService: IEnvironmentService, - lifecycleMainService: ILifecycleMainService + private readonly environmentService: IEnvironmentService ) { - super(logService, lifecycleMainService); + super(logService); } protected async doInitialize(): Promise { @@ -266,9 +248,8 @@ export class WorkspaceStorageMain extends BaseStorageMain implements IStorageMai private workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier, logService: ILogService, private readonly environmentService: IEnvironmentService, - lifecycleMainService: ILifecycleMainService ) { - super(logService, lifecycleMainService); + super(logService); } protected async doInitialize(): Promise { diff --git a/src/vs/platform/storage/electron-main/storageMainService.ts b/src/vs/platform/storage/electron-main/storageMainService.ts index f9b408032b9..e5a1e45f59d 100644 --- a/src/vs/platform/storage/electron-main/storageMainService.ts +++ b/src/vs/platform/storage/electron-main/storageMainService.ts @@ -4,11 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { once } from 'vs/base/common/functional'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; +import { ILifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { ILogService } from 'vs/platform/log/common/log'; import { GlobalStorageMain, IStorageMain, WorkspaceStorageMain } from 'vs/platform/storage/electron-main/storageMain'; +import { IWindowSettings } from 'vs/platform/windows/common/windows'; import { IEmptyWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; export const IStorageMainService = createDecorator('storageMainService'); @@ -28,15 +31,54 @@ export interface IStorageMainService { workspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier): IStorageMain; } -export class StorageMainService implements IStorageMainService { +export class StorageMainService extends Disposable implements IStorageMainService { declare readonly _serviceBrand: undefined; + private enableMainWorkspaceStorage = this.configurationService.getValue('window')?.enableExperimentalMainProcessWorkspaceStorage; + constructor( @ILogService private readonly logService: ILogService, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService + @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, + @IConfigurationService private readonly configurationService: IConfigurationService ) { + super(); + + this.registerListeners(); + } + + private registerListeners(): void { + + // Global Storage: Warmup when any window opens + (async () => { + await this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen); + + this.globalStorage.initialize(); + })(); + + // Workspace Storage: Warmup when related window with workspace loads + if (this.enableMainWorkspaceStorage) { + this._register(this.lifecycleMainService.onWillLoadWindow(async e => { + if (e.workspace) { + await this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen); + + this.workspaceStorage(e.workspace).initialize(); + } + })); + } + + // All Storage: Close when shutting down + this._register(this.lifecycleMainService.onWillShutdown(e => { + + // Global Storage + e.join(this.globalStorage.close()); + + // Workspace Storage(s) + for (const [, storage] of this.mapWorkspaceToStorage) { + e.join(storage.close()); + } + })); } //#region Global Storage @@ -50,7 +92,7 @@ export class StorageMainService implements IStorageMainService { this.logService.trace(`StorageMainService: creating global storage`); - const globalStorage = new GlobalStorageMain(this.logService, this.environmentService, this.lifecycleMainService); + const globalStorage = new GlobalStorageMain(this.logService, this.environmentService); once(globalStorage.onDidCloseStorage)(() => { this.logService.trace(`StorageMainService: closed global storage`); @@ -67,7 +109,7 @@ export class StorageMainService implements IStorageMainService { private readonly mapWorkspaceToStorage = new Map(); private createWorkspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier): IStorageMain { - const workspaceStorage = new WorkspaceStorageMain(workspace, this.logService, this.environmentService, this.lifecycleMainService); + const workspaceStorage = new WorkspaceStorageMain(workspace, this.logService, this.environmentService); return workspaceStorage; } diff --git a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts index cdde6a0aa04..3bae7df6d67 100644 --- a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts +++ b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts @@ -23,6 +23,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; import { ICodeWindow } from 'vs/platform/windows/electron-main/windows'; import { Promises } from 'vs/base/common/async'; +import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; flakySuite('StorageMainService (native)', function () { @@ -68,14 +69,16 @@ flakySuite('StorageMainService (native)', function () { await Promises.settled(joiners); } - onBeforeWindowClose = Event.None; - onBeforeWindowUnload = Event.None; + onWillLoadWindow = Event.None; + onBeforeCloseWindow = Event.None; + onBeforeUnloadWindow = Event.None; wasRestarted = false; quitRequested = false; phase = LifecycleMainPhase.Ready; + registerWindow(window: ICodeWindow): void { } async reload(window: ICodeWindow, cli?: NativeParsedArgs): Promise { } async unload(window: ICodeWindow, reason: UnloadReason): Promise { return true; } relaunch(options?: { addArgs?: string[] | undefined; removeArgs?: string[] | undefined; }): void { } @@ -169,7 +172,7 @@ flakySuite('StorageMainService (native)', function () { test('basics (global)', function () { return testStorage(() => { - const storageMainService = new StorageMainService(new NullLogService(), environmentService, new StorageTestLifecycleMainService()); + const storageMainService = new StorageMainService(new NullLogService(), environmentService, new StorageTestLifecycleMainService(), new TestConfigurationService()); return storageMainService.globalStorage; }, true); @@ -179,7 +182,7 @@ flakySuite('StorageMainService (native)', function () { const workspace = { id: generateUuid() }; return testStorage(() => { - const storageMainService = new StorageMainService(new NullLogService(), environmentService, new StorageTestLifecycleMainService()); + const storageMainService = new StorageMainService(new NullLogService(), environmentService, new StorageTestLifecycleMainService(), new TestConfigurationService()); return storageMainService.workspaceStorage(workspace); }, false); @@ -188,7 +191,7 @@ flakySuite('StorageMainService (native)', function () { test('storage closed onWillShutdown', async function () { const lifecycleMainService = new StorageTestLifecycleMainService(); const workspace = { id: generateUuid() }; - const storageMainService = new StorageMainService(new NullLogService(), environmentService, lifecycleMainService); + const storageMainService = new StorageMainService(new NullLogService(), environmentService, lifecycleMainService, new TestConfigurationService()); let storage = storageMainService.workspaceStorage(workspace); let didCloseStorage = false; diff --git a/src/vs/platform/windows/electron-main/window.ts b/src/vs/platform/windows/electron-main/window.ts index c437ab35c47..632a2db22cb 100644 --- a/src/vs/platform/windows/electron-main/window.ts +++ b/src/vs/platform/windows/electron-main/window.ts @@ -19,7 +19,7 @@ import product from 'vs/platform/product/common/product'; import { WindowMinimumSize, IWindowSettings, MenuBarVisibility, getTitleBarStyle, getMenuBarVisibility, zoomLevelToZoomFactor, INativeWindowConfiguration } from 'vs/platform/windows/common/windows'; import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; import { browserCodeLoadingCacheStrategy, isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; -import { defaultWindowState, ICodeWindow, IWindowState, WindowMode } from 'vs/platform/windows/electron-main/windows'; +import { defaultWindowState, ICodeWindow, ILoadEvent, IWindowState, WindowMode } from 'vs/platform/windows/electron-main/windows'; import { ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { IWorkspacesManagementMainService } from 'vs/platform/workspaces/electron-main/workspacesManagementMainService'; import { IBackupMainService } from 'vs/platform/backup/electron-main/backup'; @@ -80,8 +80,8 @@ export class CodeWindow extends Disposable implements ICodeWindow { private static readonly MAX_URL_LENGTH = 2 * ByteSize.MB; // https://cs.chromium.org/chromium/src/url/url_constants.cc?l=32 - private readonly _onDidLoad = this._register(new Emitter()); - readonly onDidLoad = this._onDidLoad.event; + private readonly _onWillLoad = this._register(new Emitter()); + readonly onWillLoad = this._onWillLoad.event; private readonly _onDidSignalReady = this._register(new Emitter()); readonly onDidSignalReady = this._onDidSignalReady.event; @@ -396,7 +396,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { } const closeListener = this.onDidClose(() => handle()); - const loadListener = this.onDidLoad(() => handle()); + const loadListener = this.onWillLoad(() => handle()); }); } @@ -761,7 +761,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { } // Event - this._onDidLoad.fire(); + this._onWillLoad.fire({ workspace: configuration.workspace }); } async reload(cli?: NativeParsedArgs): Promise { diff --git a/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts index 89ade1c8667..9a97d621b5c 100644 --- a/src/vs/platform/windows/electron-main/windows.ts +++ b/src/vs/platform/windows/electron-main/windows.ts @@ -60,9 +60,13 @@ export const enum WindowMode { Fullscreen } +export interface ILoadEvent { + workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined; +} + export interface ICodeWindow extends IDisposable { - readonly onDidLoad: Event; + readonly onWillLoad: Event; readonly onDidSignalReady: Event; readonly onDidClose: Event; readonly onDidDestroy: Event; diff --git a/src/vs/platform/windows/electron-main/windowsMainService.ts b/src/vs/platform/windows/electron-main/windowsMainService.ts index db2b237d45e..de3b4bf960b 100644 --- a/src/vs/platform/windows/electron-main/windowsMainService.ts +++ b/src/vs/platform/windows/electron-main/windowsMainService.ts @@ -14,7 +14,7 @@ import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; import { IStateService } from 'vs/platform/state/node/state'; import { CodeWindow } from 'vs/platform/windows/electron-main/window'; import { BrowserWindow, MessageBoxOptions, WebContents } from 'electron'; -import { ILifecycleMainService, UnloadReason, LifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; +import { ILifecycleMainService, UnloadReason, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILogService } from 'vs/platform/log/common/log'; import { IWindowSettings, IPath, isFileToOpen, isWorkspaceToOpen, isFolderToOpen, IWindowOpenable, IOpenEmptyWindowOptions, IAddFoldersRequest, IPathsToWaitFor, INativeWindowConfiguration, INativeOpenFileRequest } from 'vs/platform/windows/common/windows'; @@ -1204,7 +1204,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic createdWindow.win.webContents.on('devtools-reload-page', () => this.lifecycleMainService.reload(createdWindow)); // Lifecycle - (this.lifecycleMainService as LifecycleMainService).registerWindow(createdWindow); + this.lifecycleMainService.registerWindow(createdWindow); } // Existing window diff --git a/src/vs/platform/windows/electron-main/windowsStateHandler.ts b/src/vs/platform/windows/electron-main/windowsStateHandler.ts index cc3e5457601..75c96494b80 100644 --- a/src/vs/platform/windows/electron-main/windowsStateHandler.ts +++ b/src/vs/platform/windows/electron-main/windowsStateHandler.ts @@ -83,7 +83,7 @@ export class WindowsStateHandler extends Disposable { }); // Handle various lifecycle events around windows - this.lifecycleMainService.onBeforeWindowClose(window => this.onBeforeWindowClose(window)); + this.lifecycleMainService.onBeforeCloseWindow(window => this.onBeforeCloseWindow(window)); this.lifecycleMainService.onBeforeShutdown(() => this.onBeforeShutdown()); this.windowsMainService.onDidChangeWindowsCount(e => { if (e.newCount - e.oldCount > 0) { @@ -95,16 +95,16 @@ export class WindowsStateHandler extends Disposable { }); // try to save state before destroy because close will not fire - this.windowsMainService.onDidDestroyWindow(window => this.onBeforeWindowClose(window)); + this.windowsMainService.onDidDestroyWindow(window => this.onBeforeCloseWindow(window)); } - // Note that onBeforeShutdown() and onBeforeWindowClose() are fired in different order depending on the OS: + // Note that onBeforeShutdown() and onBeforeCloseWindow() are fired in different order depending on the OS: // - macOS: since the app will not quit when closing the last window, you will always first get - // the onBeforeShutdown() event followed by N onBeforeWindowClose() events for each window + // the onBeforeShutdown() event followed by N onBeforeCloseWindow() events for each window // - other: on other OS, closing the last window will quit the app so the order depends on the - // user interaction: closing the last window will first trigger onBeforeWindowClose() + // user interaction: closing the last window will first trigger onBeforeCloseWindow() // and then onBeforeShutdown(). Using the quit action however will first issue onBeforeShutdown() - // and then onBeforeWindowClose(). + // and then onBeforeCloseWindow(). // // Here is the behavior on different OS depending on action taken (Electron 1.7.x): // @@ -113,27 +113,27 @@ export class WindowsStateHandler extends Disposable { // - close(1): close one window via the window close button // - closeAll: close all windows via the taskbar command // - onBeforeShutdown(N): number of windows reported in this event handler - // - onBeforeWindowClose(N, M): number of windows reported and quitRequested boolean in this event handler + // - onBeforeCloseWindow(N, M): number of windows reported and quitRequested boolean in this event handler // // macOS - // - quit(1): onBeforeShutdown(1), onBeforeWindowClose(1, true) - // - quit(2): onBeforeShutdown(2), onBeforeWindowClose(2, true), onBeforeWindowClose(2, true) + // - quit(1): onBeforeShutdown(1), onBeforeCloseWindow(1, true) + // - quit(2): onBeforeShutdown(2), onBeforeCloseWindow(2, true), onBeforeCloseWindow(2, true) // - quit(0): onBeforeShutdown(0) - // - close(1): onBeforeWindowClose(1, false) + // - close(1): onBeforeCloseWindow(1, false) // // Windows - // - quit(1): onBeforeShutdown(1), onBeforeWindowClose(1, true) - // - quit(2): onBeforeShutdown(2), onBeforeWindowClose(2, true), onBeforeWindowClose(2, true) - // - close(1): onBeforeWindowClose(2, false)[not last window] - // - close(1): onBeforeWindowClose(1, false), onBeforeShutdown(0)[last window] - // - closeAll(2): onBeforeWindowClose(2, false), onBeforeWindowClose(2, false), onBeforeShutdown(0) + // - quit(1): onBeforeShutdown(1), onBeforeCloseWindow(1, true) + // - quit(2): onBeforeShutdown(2), onBeforeCloseWindow(2, true), onBeforeCloseWindow(2, true) + // - close(1): onBeforeCloseWindow(2, false)[not last window] + // - close(1): onBeforeCloseWindow(1, false), onBeforeShutdown(0)[last window] + // - closeAll(2): onBeforeCloseWindow(2, false), onBeforeCloseWindow(2, false), onBeforeShutdown(0) // // Linux - // - quit(1): onBeforeShutdown(1), onBeforeWindowClose(1, true) - // - quit(2): onBeforeShutdown(2), onBeforeWindowClose(2, true), onBeforeWindowClose(2, true) - // - close(1): onBeforeWindowClose(2, false)[not last window] - // - close(1): onBeforeWindowClose(1, false), onBeforeShutdown(0)[last window] - // - closeAll(2): onBeforeWindowClose(2, false), onBeforeWindowClose(2, false), onBeforeShutdown(0) + // - quit(1): onBeforeShutdown(1), onBeforeCloseWindow(1, true) + // - quit(2): onBeforeShutdown(2), onBeforeCloseWindow(2, true), onBeforeCloseWindow(2, true) + // - close(1): onBeforeCloseWindow(2, false)[not last window] + // - close(1): onBeforeCloseWindow(1, false), onBeforeShutdown(0)[last window] + // - closeAll(2): onBeforeCloseWindow(2, false), onBeforeCloseWindow(2, false), onBeforeShutdown(0) // private onBeforeShutdown(): void { this.shuttingDown = true; @@ -185,7 +185,7 @@ export class WindowsStateHandler extends Disposable { } // See note on #onBeforeShutdown() for details how these events are flowing - private onBeforeWindowClose(window: ICodeWindow): void { + private onBeforeCloseWindow(window: ICodeWindow): void { if (this.lifecycleMainService.quitRequested) { return; // during quit, many windows close in parallel so let it be handled in the before-quit handler } diff --git a/src/vs/platform/windows/test/electron-main/window.test.ts b/src/vs/platform/windows/test/electron-main/windowsFinder.test.ts similarity index 97% rename from src/vs/platform/windows/test/electron-main/window.test.ts rename to src/vs/platform/windows/test/electron-main/windowsFinder.test.ts index b1aa09b7e13..634fa2c810d 100644 --- a/src/vs/platform/windows/test/electron-main/window.test.ts +++ b/src/vs/platform/windows/test/electron-main/windowsFinder.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import { join } from 'vs/base/common/path'; import { findWindowOnFile } from 'vs/platform/windows/electron-main/windowsFinder'; -import { ICodeWindow, IWindowState } from 'vs/platform/windows/electron-main/windows'; +import { ICodeWindow, ILoadEvent, IWindowState } from 'vs/platform/windows/electron-main/windows'; import { IWorkspaceIdentifier, toWorkspaceFolders } from 'vs/platform/workspaces/common/workspaces'; import { URI } from 'vs/base/common/uri'; import { getPathFromAmdModule } from 'vs/base/common/amd'; @@ -32,7 +32,7 @@ suite('WindowsFinder', () => { function createTestCodeWindow(options: { lastFocusTime: number, openedFolderUri?: URI, openedWorkspace?: IWorkspaceIdentifier }): ICodeWindow { return new class implements ICodeWindow { - onDidLoad: Event = Event.None; + onWillLoad: Event = Event.None; onDidSignalReady: Event = Event.None; onDidClose: Event = Event.None; onDidDestroy: Event = Event.None; From 1bb2e0a9babcb2a960a1a479e21d2849d83c82e0 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 16 Feb 2021 10:47:36 +0100 Subject: [PATCH 185/325] storage - use inMemory storage for tests --- .../storage/electron-main/storageMain.ts | 21 +++-- .../electron-main/storageMainService.ts | 20 +++-- .../electron-main/storageMainService.test.ts | 82 ++++--------------- 3 files changed, 47 insertions(+), 76 deletions(-) diff --git a/src/vs/platform/storage/electron-main/storageMain.ts b/src/vs/platform/storage/electron-main/storageMain.ts index 0b4cec2c83d..9d1f5c1b6ce 100644 --- a/src/vs/platform/storage/electron-main/storageMain.ts +++ b/src/vs/platform/storage/electron-main/storageMain.ts @@ -17,6 +17,15 @@ import { currentSessionDateStorageKey, firstSessionDateStorageKey, instanceStora import { generateUuid } from 'vs/base/common/uuid'; import { IEmptyWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +export interface IStorageMainOptions { + + /** + * If enabled, storage will not persist to disk + * but into memory. + */ + useInMemoryStorage?: boolean; +} + /** * Provides access to global and workspace storage from the * electron-main side that is the owner of all storage connections. @@ -184,6 +193,7 @@ export class GlobalStorageMain extends BaseStorageMain implements IStorageMain { private static readonly STORAGE_NAME = 'state.vscdb'; constructor( + private readonly options: IStorageMainOptions, logService: ILogService, private readonly environmentService: IEnvironmentService ) { @@ -192,8 +202,8 @@ export class GlobalStorageMain extends BaseStorageMain implements IStorageMain { protected async doInitialize(): Promise { let storagePath: string; - if (!!this.environmentService.extensionTestsLocationURI) { - storagePath = SQLiteStorageDatabase.IN_MEMORY_PATH; // no storage during extension tests! + if (this.options.useInMemoryStorage) { + storagePath = SQLiteStorageDatabase.IN_MEMORY_PATH; } else { storagePath = join(this.environmentService.globalStorageHome.fsPath, GlobalStorageMain.STORAGE_NAME); } @@ -246,8 +256,9 @@ export class WorkspaceStorageMain extends BaseStorageMain implements IStorageMai constructor( private workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier, + private readonly options: IStorageMainOptions, logService: ILogService, - private readonly environmentService: IEnvironmentService, + private readonly environmentService: IEnvironmentService ) { super(logService); } @@ -273,8 +284,8 @@ export class WorkspaceStorageMain extends BaseStorageMain implements IStorageMai private async prepareWorkspaceStorageFolder(): Promise<{ storageFilePath: string, wasCreated: boolean }> { - // Return early with in-memory when running extension tests - if (!!this.environmentService.extensionTestsLocationURI) { + // Return early if using inMemory storage + if (this.options.useInMemoryStorage) { return { storageFilePath: SQLiteStorageDatabase.IN_MEMORY_PATH, wasCreated: true }; } diff --git a/src/vs/platform/storage/electron-main/storageMainService.ts b/src/vs/platform/storage/electron-main/storageMainService.ts index e5a1e45f59d..6b50b94256a 100644 --- a/src/vs/platform/storage/electron-main/storageMainService.ts +++ b/src/vs/platform/storage/electron-main/storageMainService.ts @@ -10,7 +10,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ILifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { ILogService } from 'vs/platform/log/common/log'; -import { GlobalStorageMain, IStorageMain, WorkspaceStorageMain } from 'vs/platform/storage/electron-main/storageMain'; +import { GlobalStorageMain, IStorageMain, IStorageMainOptions, WorkspaceStorageMain } from 'vs/platform/storage/electron-main/storageMain'; import { IWindowSettings } from 'vs/platform/windows/common/windows'; import { IEmptyWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; @@ -35,8 +35,6 @@ export class StorageMainService extends Disposable implements IStorageMainServic declare readonly _serviceBrand: undefined; - private enableMainWorkspaceStorage = this.configurationService.getValue('window')?.enableExperimentalMainProcessWorkspaceStorage; - constructor( @ILogService private readonly logService: ILogService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @@ -48,6 +46,16 @@ export class StorageMainService extends Disposable implements IStorageMainServic this.registerListeners(); } + protected getStorageOptions(): IStorageMainOptions { + return { + useInMemoryStorage: !!this.environmentService.extensionTestsLocationURI // no storage during extension tests! + }; + } + + protected enableMainWorkspaceStorage(): boolean { + return !!(this.configurationService.getValue('window')?.enableExperimentalMainProcessWorkspaceStorage); + } + private registerListeners(): void { // Global Storage: Warmup when any window opens @@ -58,7 +66,7 @@ export class StorageMainService extends Disposable implements IStorageMainServic })(); // Workspace Storage: Warmup when related window with workspace loads - if (this.enableMainWorkspaceStorage) { + if (this.enableMainWorkspaceStorage()) { this._register(this.lifecycleMainService.onWillLoadWindow(async e => { if (e.workspace) { await this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen); @@ -92,7 +100,7 @@ export class StorageMainService extends Disposable implements IStorageMainServic this.logService.trace(`StorageMainService: creating global storage`); - const globalStorage = new GlobalStorageMain(this.logService, this.environmentService); + const globalStorage = new GlobalStorageMain(this.getStorageOptions(), this.logService, this.environmentService); once(globalStorage.onDidCloseStorage)(() => { this.logService.trace(`StorageMainService: closed global storage`); @@ -109,7 +117,7 @@ export class StorageMainService extends Disposable implements IStorageMainServic private readonly mapWorkspaceToStorage = new Map(); private createWorkspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier): IStorageMain { - const workspaceStorage = new WorkspaceStorageMain(workspace, this.logService, this.environmentService); + const workspaceStorage = new WorkspaceStorageMain(workspace, this.getStorageOptions(), this.logService, this.environmentService); return workspaceStorage; } diff --git a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts index 3bae7df6d67..0461769cede 100644 --- a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts +++ b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts @@ -3,46 +3,34 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { promises } from 'fs'; -import { tmpdir } from 'os'; import { notStrictEqual, strictEqual } from 'assert'; -import { URI } from 'vs/base/common/uri'; -import { rimraf } from 'vs/base/node/pfs'; -import { flakySuite, getRandomTestPath } from 'vs/base/test/node/testUtils'; import { OPTIONS, parseArgs } from 'vs/platform/environment/node/argv'; import { NativeEnvironmentService } from 'vs/platform/environment/node/environmentService'; import { NullLogService } from 'vs/platform/log/common/log'; import { StorageMainService } from 'vs/platform/storage/electron-main/storageMainService'; import { currentSessionDateStorageKey, firstSessionDateStorageKey, instanceStorageKey } from 'vs/platform/telemetry/common/telemetry'; -import { IStorageChangeEvent, IStorageMain } from 'vs/platform/storage/electron-main/storageMain'; +import { IStorageChangeEvent, IStorageMain, IStorageMainOptions } from 'vs/platform/storage/electron-main/storageMain'; import { generateUuid } from 'vs/base/common/uuid'; import { IS_NEW_KEY } from 'vs/platform/storage/common/storage'; -import { joinPath } from 'vs/base/common/resources'; import { ILifecycleMainService, LifecycleMainPhase, ShutdownEvent, UnloadReason } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { Emitter, Event } from 'vs/base/common/event'; import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; import { ICodeWindow } from 'vs/platform/windows/electron-main/windows'; -import { Promises } from 'vs/base/common/async'; +import { Promises, timeout } from 'vs/base/common/async'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; -flakySuite('StorageMainService (native)', function () { +suite('StorageMainService (native)', function () { - class StorageTestEnvironmentService extends NativeEnvironmentService { + class TestStorageMainService extends StorageMainService { - constructor(private globalStorageFolderPath: URI, private workspaceStorageFolderPath: URI, private _extensionsPath: string) { - super(parseArgs(process.argv, OPTIONS)); + protected getStorageOptions(): IStorageMainOptions { + return { + useInMemoryStorage: true + }; } - get globalStorageHome(): URI { - return this.globalStorageFolderPath; - } - - get workspaceStorageHome(): URI { - return this.workspaceStorageFolderPath; - } - - get extensionsPath(): string { - return this._extensionsPath; + protected enableMainWorkspaceStorage(): boolean { + return true; } } @@ -87,28 +75,7 @@ flakySuite('StorageMainService (native)', function () { async when(phase: LifecycleMainPhase): Promise { } } - let testDir: string; - let environmentService: StorageTestEnvironmentService; - - setup(async () => { - testDir = getRandomTestPath(tmpdir(), 'vsctests', 'storageMainService'); - - await promises.mkdir(testDir, { recursive: true }); - - const globalStorageFolder = joinPath(URI.file(testDir), 'globalStorage'); - const workspaceStorageFolder = joinPath(URI.file(testDir), 'workspaceStorage'); - - await promises.mkdir(globalStorageFolder.fsPath, { recursive: true }); - - environmentService = new StorageTestEnvironmentService(globalStorageFolder, workspaceStorageFolder, testDir); - }); - - teardown(() => { - return rimraf(testDir); - }); - - async function testStorage(storageFn: () => IStorageMain, isGlobal: boolean): Promise { - let storage = storageFn(); + async function testStorage(storage: IStorageMain, isGlobal: boolean): Promise { // Telemetry: added after init if (isGlobal) { @@ -155,43 +122,27 @@ flakySuite('StorageMainService (native)', function () { // Close await storage.close(); - strictEqual(storageDidClose, true); - storageChangeListener.dispose(); storageCloseListener.dispose(); - - // Reopen - storage = storageFn(); - await storage.initialize(); - - strictEqual(storage.getNumber('barNumber'), 55); - strictEqual(storage.getBoolean('barBoolean'), true); - - await storage.close(); } test('basics (global)', function () { - return testStorage(() => { - const storageMainService = new StorageMainService(new NullLogService(), environmentService, new StorageTestLifecycleMainService(), new TestConfigurationService()); + const storageMainService = new TestStorageMainService(new NullLogService(), new NativeEnvironmentService(parseArgs(process.argv, OPTIONS)), new StorageTestLifecycleMainService(), new TestConfigurationService()); - return storageMainService.globalStorage; - }, true); + return testStorage(storageMainService.globalStorage, true); }); test('basics (workspace)', function () { const workspace = { id: generateUuid() }; + const storageMainService = new TestStorageMainService(new NullLogService(), new NativeEnvironmentService(parseArgs(process.argv, OPTIONS)), new StorageTestLifecycleMainService(), new TestConfigurationService()); - return testStorage(() => { - const storageMainService = new StorageMainService(new NullLogService(), environmentService, new StorageTestLifecycleMainService(), new TestConfigurationService()); - - return storageMainService.workspaceStorage(workspace); - }, false); + return testStorage(storageMainService.workspaceStorage(workspace), false); }); test('storage closed onWillShutdown', async function () { const lifecycleMainService = new StorageTestLifecycleMainService(); const workspace = { id: generateUuid() }; - const storageMainService = new StorageMainService(new NullLogService(), environmentService, lifecycleMainService, new TestConfigurationService()); + const storageMainService = new TestStorageMainService(new NullLogService(), new NativeEnvironmentService(parseArgs(process.argv, OPTIONS)), lifecycleMainService, new TestConfigurationService()); let storage = storageMainService.workspaceStorage(workspace); let didCloseStorage = false; @@ -203,6 +154,7 @@ flakySuite('StorageMainService (native)', function () { await storage.initialize(); + await timeout(0); await lifecycleMainService.fireOnWillShutdown(); strictEqual(didCloseStorage, true); From 266e475931645a25cd1601a5dd3b0914911d95ea Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 16 Feb 2021 11:09:23 +0100 Subject: [PATCH 186/325] before removing cell documents capture its API objects, after inserting cell documents capture its API objects, fixes https://github.com/microsoft/vscode/issues/116711 --- .../api/common/extHostNotebookDocument.ts | 8 +-- .../test/browser/api/extHostNotebook.test.ts | 50 ++++++++++++++++++- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/api/common/extHostNotebookDocument.ts b/src/vs/workbench/api/common/extHostNotebookDocument.ts index 3e9e9e41a85..e9e715885c4 100644 --- a/src/vs/workbench/api/common/extHostNotebookDocument.ts +++ b/src/vs/workbench/api/common/extHostNotebookDocument.ts @@ -18,13 +18,13 @@ import * as vscode from 'vscode'; class RawContentChangeEvent { - constructor(readonly start: number, readonly deletedCount: number, readonly deletedItems: ExtHostCell[], readonly items: ExtHostCell[]) { } + constructor(readonly start: number, readonly deletedCount: number, readonly deletedItems: vscode.NotebookCell[], readonly items: ExtHostCell[]) { } static asApiEvent(event: RawContentChangeEvent): vscode.NotebookCellsChangeData { return Object.freeze({ start: event.start, deletedCount: event.deletedCount, - deletedItems: event.deletedItems.map(data => data.cell), + deletedItems: event.deletedItems, items: event.items.map(data => data.cell) }); } @@ -252,12 +252,14 @@ export class ExtHostNotebookDocument extends Disposable { this._cellDisposableMapping.delete(this._cells[j].handle); } + const changeEvent = new RawContentChangeEvent(splice[0], splice[1], [], newCells); const deletedItems = this._cells.splice(splice[0], splice[1], ...newCells); for (let cell of deletedItems) { removedCellDocuments.push(cell.uri); + changeEvent.deletedItems.push(cell.cell); } - contentChangeEvents.push(new RawContentChangeEvent(splice[0], splice[1], deletedItems, newCells)); + contentChangeEvents.push(changeEvent); }); this._documentsAndEditors.acceptDocumentsAndEditorsDelta({ diff --git a/src/vs/workbench/test/browser/api/extHostNotebook.test.ts b/src/vs/workbench/test/browser/api/extHostNotebook.test.ts index 7619a7b337b..a85f77ba805 100644 --- a/src/vs/workbench/test/browser/api/extHostNotebook.test.ts +++ b/src/vs/workbench/test/browser/api/extHostNotebook.test.ts @@ -21,6 +21,7 @@ import { nullExtensionDescription } from 'vs/workbench/services/extensions/commo import { isEqual } from 'vs/base/common/resources'; import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths'; import { generateUuid } from 'vs/base/common/uuid'; +import { Event } from 'vs/base/common/event'; suite('NotebookCell#Document', function () { @@ -33,9 +34,11 @@ suite('NotebookCell#Document', function () { const notebookUri = URI.parse('test:///notebook.file'); const disposables = new DisposableStore(); - setup(async function () { + teardown(function () { disposables.clear(); + }); + setup(async function () { rpcProtocol = new TestRPCProtocol(); rpcProtocol.set(MainContext.MainThreadCommands, new class extends mock() { $registerCommand() { } @@ -305,4 +308,49 @@ suite('NotebookCell#Document', function () { assert.strictEqual(notebook.notebookDocument.cells.length, 3); assert.strictEqual(second.index, 2); }); + + test('ERR MISSING extHostDocument for notebook cell: #116711', async function () { + + const p = Event.toPromise(extHostNotebooks.onDidChangeNotebookCells); + + // DON'T call this, make sure the cell-documents have not been created yet + // assert.strictEqual(notebook.notebookDocument.cells.length, 2); + + extHostNotebooks.$acceptModelChanged(notebook.uri, { + versionId: 100, + rawEvents: [{ + kind: NotebookCellsChangeType.ModelChange, + changes: [[0, 2, [{ + handle: 3, + uri: CellUri.generate(notebookUri, 3), + source: ['### Heading'], + eol: '\n', + language: 'markdown', + cellKind: CellKind.Markdown, + outputs: [], + }, { + handle: 4, + uri: CellUri.generate(notebookUri, 4), + source: ['console.log("aaa")', 'console.log("bbb")'], + eol: '\n', + language: 'javascript', + cellKind: CellKind.Code, + outputs: [], + }]]] + }] + }, false); + + assert.strictEqual(notebook.notebookDocument.cells.length, 2); + + const event = await p; + + assert.strictEqual(event.document === notebook.notebookDocument, true); + assert.strictEqual(event.changes.length, 1); + assert.strictEqual(event.changes[0].deletedCount, 2); + assert.strictEqual(event.changes[0].deletedItems[0].document.isClosed, true); + assert.strictEqual(event.changes[0].deletedItems[1].document.isClosed, true); + assert.strictEqual(event.changes[0].items.length, 2); + assert.strictEqual(event.changes[0].items[0].document.isClosed, false); + assert.strictEqual(event.changes[0].items[1].document.isClosed, false); + }); }); From 5e74ad5430203eadf89fd8e99695f4ebdb0e62ad Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 16 Feb 2021 11:12:08 +0100 Subject: [PATCH 187/325] storage - fix unused storage variable in tests --- .../storage/test/electron-main/storageMainService.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts index 0461769cede..3aa295edca7 100644 --- a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts +++ b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts @@ -122,6 +122,8 @@ suite('StorageMainService (native)', function () { // Close await storage.close(); + strictEqual(storageDidClose, true); + storageChangeListener.dispose(); storageCloseListener.dispose(); } From 3dab064342ec56fbe80532ec32cae5709608b160 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru Date: Tue, 16 Feb 2021 11:25:51 +0100 Subject: [PATCH 188/325] Move component governance to compile stage --- build/azure-pipelines/darwin/product-build-darwin.yml | 4 ---- build/azure-pipelines/linux/product-build-alpine.yml | 4 ---- build/azure-pipelines/linux/product-build-linux.yml | 4 ---- build/azure-pipelines/product-compile.yml | 4 ++++ build/azure-pipelines/win32/product-build-win32.yml | 4 ---- 5 files changed, 4 insertions(+), 16 deletions(-) diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index 1f3cba946bd..3bbbbb461e1 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -388,7 +388,3 @@ steps: displayName: Upload configuration (for Bing settings search) condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), ne(variables['VSCODE_PUBLISH'], 'false')) continueOnError: true - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: "Component Detection" - continueOnError: true diff --git a/build/azure-pipelines/linux/product-build-alpine.yml b/build/azure-pipelines/linux/product-build-alpine.yml index 7e3aea8d231..4a1b8a2c64a 100644 --- a/build/azure-pipelines/linux/product-build-alpine.yml +++ b/build/azure-pipelines/linux/product-build-alpine.yml @@ -133,7 +133,3 @@ steps: artifact: vscode-server-linux-alpine-web displayName: Publish web server archive condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: "Component Detection" - continueOnError: true diff --git a/build/azure-pipelines/linux/product-build-linux.yml b/build/azure-pipelines/linux/product-build-linux.yml index 1d26cee26f4..d0c8e0894e7 100644 --- a/build/azure-pipelines/linux/product-build-linux.yml +++ b/build/azure-pipelines/linux/product-build-linux.yml @@ -287,7 +287,3 @@ steps: artifactName: "snap-$(VSCODE_ARCH)" targetPath: .build/linux/snap-tarball condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: "Component Detection" - continueOnError: true diff --git a/build/azure-pipelines/product-compile.yml b/build/azure-pipelines/product-compile.yml index 7855cde1663..4f2024a6209 100644 --- a/build/azure-pipelines/product-compile.yml +++ b/build/azure-pipelines/product-compile.yml @@ -137,3 +137,7 @@ steps: targetPath: $(Build.ArtifactStagingDirectory)/compilation.tar.gz artifactName: Compilation displayName: Publish compilation artifact + + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: "Component Detection" + continueOnError: true diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index 7076ebf13b0..5ca1f825865 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -322,7 +322,3 @@ steps: artifact: vscode-server-win32-$(VSCODE_ARCH)-web displayName: Publish web server archive condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: "Component Detection" - continueOnError: true From 58e22bc5226e156f7ec356650547871dd4477646 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 16 Feb 2021 11:27:26 +0100 Subject: [PATCH 189/325] window - type win as null if disposed --- src/vs/code/electron-main/auth.ts | 4 ++-- .../electron-main/extensionHostDebugIpc.ts | 11 ++++++--- .../platform/driver/electron-main/driver.ts | 4 ++-- .../launch/electron-main/launchMainService.ts | 4 +++- .../electron-main/lifecycleMainService.ts | 6 +++-- .../electron-main/nativeHostMainService.ts | 24 +++++++++---------- .../electron-main/webviewMainService.ts | 2 +- .../platform/windows/electron-main/window.ts | 22 ++++++++--------- .../platform/windows/electron-main/windows.ts | 2 +- .../electron-main/windowsMainService.ts | 8 ++++--- .../test/electron-main/windowsFinder.test.ts | 2 +- 11 files changed, 50 insertions(+), 39 deletions(-) diff --git a/src/vs/code/electron-main/auth.ts b/src/vs/code/electron-main/auth.ts index b9669f983c7..70df692cf81 100644 --- a/src/vs/code/electron-main/auth.ts +++ b/src/vs/code/electron-main/auth.ts @@ -201,7 +201,7 @@ export class ProxyAuthHandler extends Disposable { const proxyAuthResponseHandler = async (event: ElectronEvent, channel: string, reply: Credentials & { remember: boolean } | undefined /* canceled */) => { if (channel === payload.replyChannel) { this.logService.trace(`auth#doResolveProxyCredentials - exit - received credentials from window ${window.id}`); - window.win.webContents.off('ipc-message', proxyAuthResponseHandler); + window.win?.webContents.off('ipc-message', proxyAuthResponseHandler); // We got credentials from the window if (reply) { @@ -229,7 +229,7 @@ export class ProxyAuthHandler extends Disposable { } }; - window.win.webContents.on('ipc-message', proxyAuthResponseHandler); + window.win?.webContents.on('ipc-message', proxyAuthResponseHandler); }); // Remember credentials for the session in case diff --git a/src/vs/platform/debug/electron-main/extensionHostDebugIpc.ts b/src/vs/platform/debug/electron-main/extensionHostDebugIpc.ts index f0ac255cb2a..9d37b27980d 100644 --- a/src/vs/platform/debug/electron-main/extensionHostDebugIpc.ts +++ b/src/vs/platform/debug/electron-main/extensionHostDebugIpc.ts @@ -43,7 +43,12 @@ export class ElectronExtensionHostDebugBroadcastChannel extends Extens return {}; } - const debug = codeWindow.win.webContents.debugger; + const win = codeWindow.win; + if (!win) { + return {}; + } + + const debug = win.webContents.debugger; let listeners = debug.isAttached() ? Infinity : 0; const server = createServer(listener => { @@ -61,7 +66,7 @@ export class ElectronExtensionHostDebugBroadcastChannel extends Extens const onMessage = (_event: Event, method: string, params: unknown, sessionId?: string) => writeMessage(({ method, params, sessionId })); - codeWindow.win.on('close', () => { + win.on('close', () => { debug.removeListener('message', onMessage); listener.end(); closed = true; @@ -103,7 +108,7 @@ export class ElectronExtensionHostDebugBroadcastChannel extends Extens }); await new Promise(r => server.listen(0, r)); - codeWindow.win.on('close', () => server.close()); + win.on('close', () => server.close()); return { rendererDebugPort: (server.address() as AddressInfo).port }; } diff --git a/src/vs/platform/driver/electron-main/driver.ts b/src/vs/platform/driver/electron-main/driver.ts index d4501169882..f2f76df80c3 100644 --- a/src/vs/platform/driver/electron-main/driver.ts +++ b/src/vs/platform/driver/electron-main/driver.ts @@ -62,7 +62,7 @@ export class Driver implements IDriver, IWindowDriverRegistry { await this.whenUnfrozen(windowId); const window = this.windowsMainService.getWindowById(windowId); - if (!window) { + if (!window?.win) { throw new Error('Invalid window'); } const webContents = window.win.webContents; @@ -101,7 +101,7 @@ export class Driver implements IDriver, IWindowDriverRegistry { } const window = this.windowsMainService.getWindowById(windowId); - if (!window) { + if (!window?.win) { throw new Error('Invalid window'); } const webContents = window.win.webContents; diff --git a/src/vs/platform/launch/electron-main/launchMainService.ts b/src/vs/platform/launch/electron-main/launchMainService.ts index 0ec1d10331c..c613f990407 100644 --- a/src/vs/platform/launch/electron-main/launchMainService.ts +++ b/src/vs/platform/launch/electron-main/launchMainService.ts @@ -21,6 +21,7 @@ import { IMainProcessInfo, IWindowInfo } from 'vs/platform/launch/common/launch' import { isLaunchedFromCli } from 'vs/platform/environment/node/argvHelper'; import { CancellationToken } from 'vs/base/common/cancellation'; import { isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { assertIsDefined } from 'vs/base/common/types'; export const ID = 'launchMainService'; export const ILaunchMainService = createDecorator(ID); @@ -293,8 +294,9 @@ export class LaunchMainService implements ILaunchMainService { private codeWindowToInfo(window: ICodeWindow): IWindowInfo { const folderURIs = this.getFolderURIs(window); + const win = assertIsDefined(window.win); - return this.browserWindowToInfo(window.win, folderURIs, window.remoteAuthority); + return this.browserWindowToInfo(win, folderURIs, window.remoteAuthority); } private browserWindowToInfo(window: BrowserWindow, folderURIs: URI[] = [], remoteAuthority?: string): IWindowInfo { diff --git a/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts b/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts index 6d9a34dba09..82f80545895 100644 --- a/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts +++ b/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts @@ -15,6 +15,7 @@ import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { Promises, Barrier, timeout } from 'vs/base/common/async'; import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { assertIsDefined } from 'vs/base/common/types'; export const ILifecycleMainService = createDecorator('lifecycleMainService'); @@ -343,7 +344,8 @@ export class LifecycleMainService extends Disposable implements ILifecycleMainSe windowListeners.add(window.onWillLoad(e => this._onWillLoadWindow.fire({ window, workspace: e.workspace }))); // Window Before Closing: Main -> Renderer - window.win.on('close', e => { + const win = assertIsDefined(window.win); + win.on('close', e => { // The window already acknowledged to be closed const windowId = window.id; @@ -375,7 +377,7 @@ export class LifecycleMainService extends Disposable implements ILifecycleMainSe }); // Window After Closing - window.win.on('closed', () => { + win.on('closed', () => { this.logService.trace(`Lifecycle#window.on('closed') - window ID ${window.id}`); // update window count diff --git a/src/vs/platform/native/electron-main/nativeHostMainService.ts b/src/vs/platform/native/electron-main/nativeHostMainService.ts index 929af851987..ba9d54e54fd 100644 --- a/src/vs/platform/native/electron-main/nativeHostMainService.ts +++ b/src/vs/platform/native/electron-main/nativeHostMainService.ts @@ -105,7 +105,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain return windows.map(window => ({ id: window.id, workspace: window.openedWorkspace, - title: window.win.getTitle(), + title: window.win?.getTitle() ?? '', filename: window.getRepresentedFilename(), dirty: window.isDocumentEdited() })); @@ -176,7 +176,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain async isMaximized(windowId: number | undefined): Promise { const window = this.windowById(windowId); - if (window) { + if (window?.win) { return window.win.isMaximized(); } @@ -185,21 +185,21 @@ export class NativeHostMainService extends Disposable implements INativeHostMain async maximizeWindow(windowId: number | undefined): Promise { const window = this.windowById(windowId); - if (window) { + if (window?.win) { window.win.maximize(); } } async unmaximizeWindow(windowId: number | undefined): Promise { const window = this.windowById(windowId); - if (window) { + if (window?.win) { window.win.unmaximize(); } } async minimizeWindow(windowId: number | undefined): Promise { const window = this.windowById(windowId); - if (window) { + if (window?.win) { window.win.minimize(); } } @@ -217,7 +217,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain async setMinimumSize(windowId: number | undefined, width: number | undefined, height: number | undefined): Promise { const window = this.windowById(windowId); - if (window) { + if (window?.win) { const [windowWidth, windowHeight] = window.win.getSize(); const [minWindowWidth, minWindowHeight] = window.win.getMinimumSize(); const [newMinWindowWidth, newMinWindowHeight] = [width ?? minWindowWidth, height ?? minWindowHeight]; @@ -250,7 +250,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain private toBrowserWindow(windowId: number | undefined): BrowserWindow | undefined { const window = this.windowById(windowId); - if (window) { + if (window?.win) { return window.win; } @@ -563,7 +563,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain async closeWindowById(currentWindowId: number | undefined, targetWindowId?: number | undefined): Promise { const window = this.windowById(targetWindowId); - if (window) { + if (window?.win) { return window.win.close(); } } @@ -573,7 +573,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain // If the user selected to exit from an extension development host window, do not quit, but just // close the window unless this is the last window that is opened. const window = this.windowsMainService.getLastActiveWindow(); - if (window?.isExtensionDevelopmentHost && this.windowsMainService.getWindowCount() > 1) { + if (window?.isExtensionDevelopmentHost && this.windowsMainService.getWindowCount() > 1 && window.win) { window.win.close(); } @@ -609,14 +609,14 @@ export class NativeHostMainService extends Disposable implements INativeHostMain async openDevTools(windowId: number | undefined, options?: OpenDevToolsOptions): Promise { const window = this.windowById(windowId); - if (window) { + if (window?.win) { window.win.webContents.openDevTools(options); } } async toggleDevTools(windowId: number | undefined): Promise { const window = this.windowById(windowId); - if (window) { + if (window?.win) { const contents = window.win.webContents; contents.toggleDevTools(); } @@ -624,7 +624,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain async sendInputEvent(windowId: number | undefined, event: MouseInputEvent): Promise { const window = this.windowById(windowId); - if (window && (event.type === 'mouseDown' || event.type === 'mouseUp')) { + if (window?.win && (event.type === 'mouseDown' || event.type === 'mouseUp')) { window.win.webContents.sendInputEvent(event); } } diff --git a/src/vs/platform/webview/electron-main/webviewMainService.ts b/src/vs/platform/webview/electron-main/webviewMainService.ts index f569607a424..dd3984d4ba5 100644 --- a/src/vs/platform/webview/electron-main/webviewMainService.ts +++ b/src/vs/platform/webview/electron-main/webviewMainService.ts @@ -87,7 +87,7 @@ export class WebviewMainService extends Disposable implements IWebviewManagerSer if (typeof (id as WebviewWindowId).windowId === 'number') { const { windowId } = (id as WebviewWindowId); const window = this.windowsMainService.getWindowById(windowId); - if (!window) { + if (!window?.win) { throw new Error(`Invalid windowId: ${windowId}`); } contents = window.win.webContents; diff --git a/src/vs/platform/windows/electron-main/window.ts b/src/vs/platform/windows/electron-main/window.ts index 632a2db22cb..a78accbef8e 100644 --- a/src/vs/platform/windows/electron-main/window.ts +++ b/src/vs/platform/windows/electron-main/window.ts @@ -285,7 +285,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { get id(): number { return this._id; } private _win: BrowserWindow; - get win(): BrowserWindow { return this._win; } + get win(): BrowserWindow | null { return this._win; } get hasHiddenTitleBarStyle(): boolean { return !!this.hiddenTitleBarStyle; } @@ -297,7 +297,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { setRepresentedFilename(filename: string): void { if (isMacintosh) { - this.win.setRepresentedFilename(filename); + this._win.setRepresentedFilename(filename); } else { this.representedFilename = filename; } @@ -305,7 +305,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { getRepresentedFilename(): string | undefined { if (isMacintosh) { - return this.win.getRepresentedFilename(); + return this._win.getRepresentedFilename(); } return this.representedFilename; @@ -680,7 +680,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { } addTabbedWindow(window: ICodeWindow): void { - if (isMacintosh) { + if (isMacintosh && window.win) { this._win.addTabbedWindow(window.win); } } @@ -1262,26 +1262,26 @@ export class CodeWindow extends Disposable implements ICodeWindow { const action = systemPreferences.getUserDefault('AppleActionOnDoubleClick', 'string'); switch (action) { case 'Minimize': - this.win.minimize(); + this._win.minimize(); break; case 'None': break; case 'Maximize': default: - if (this.win.isMaximized()) { - this.win.unmaximize(); + if (this._win.isMaximized()) { + this._win.unmaximize(); } else { - this.win.maximize(); + this._win.maximize(); } } } // Linux/Windows: just toggle maximize/minimized state else { - if (this.win.isMaximized()) { - this.win.unmaximize(); + if (this._win.isMaximized()) { + this._win.unmaximize(); } else { - this.win.maximize(); + this._win.maximize(); } } } diff --git a/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts index 9a97d621b5c..5a1446b4c4f 100644 --- a/src/vs/platform/windows/electron-main/windows.ts +++ b/src/vs/platform/windows/electron-main/windows.ts @@ -74,7 +74,7 @@ export interface ICodeWindow extends IDisposable { readonly whenClosedOrLoaded: Promise; readonly id: number; - readonly win: BrowserWindow; + readonly win: BrowserWindow | null; /* `null` after being disposed */ readonly config: INativeWindowConfiguration | undefined; readonly openedWorkspace?: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier; diff --git a/src/vs/platform/windows/electron-main/windowsMainService.ts b/src/vs/platform/windows/electron-main/windowsMainService.ts index de3b4bf960b..f68cf41be11 100644 --- a/src/vs/platform/windows/electron-main/windowsMainService.ts +++ b/src/vs/platform/windows/electron-main/windowsMainService.ts @@ -35,7 +35,7 @@ import { getSingleFolderWorkspaceIdentifier, getWorkspaceIdentifier, IWorkspaces import { once } from 'vs/base/common/functional'; import { Disposable } from 'vs/base/common/lifecycle'; import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogMainService'; -import { withNullAsUndefined } from 'vs/base/common/types'; +import { assertIsDefined, withNullAsUndefined } from 'vs/base/common/types'; import { isWindowsDriveLetter, toSlashes, parseLineAndColumnAware, sanitizeFilePath } from 'vs/base/common/extpath'; import { CharCode } from 'vs/base/common/charCode'; import { getPathLabel } from 'vs/base/common/labels'; @@ -1200,8 +1200,10 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic once(createdWindow.onDidSignalReady)(() => this._onDidSignalReadyWindow.fire(createdWindow)); once(createdWindow.onDidClose)(() => this.onWindowClosed(createdWindow)); once(createdWindow.onDidDestroy)(() => this._onDidDestroyWindow.fire(createdWindow)); - createdWindow.win.webContents.removeAllListeners('devtools-reload-page'); // remove built in listener so we can handle this on our own - createdWindow.win.webContents.on('devtools-reload-page', () => this.lifecycleMainService.reload(createdWindow)); + + const webContents = assertIsDefined(createdWindow.win?.webContents); + webContents.removeAllListeners('devtools-reload-page'); // remove built in listener so we can handle this on our own + webContents.on('devtools-reload-page', () => this.lifecycleMainService.reload(createdWindow)); // Lifecycle this.lifecycleMainService.registerWindow(createdWindow); diff --git a/src/vs/platform/windows/test/electron-main/windowsFinder.test.ts b/src/vs/platform/windows/test/electron-main/windowsFinder.test.ts index 634fa2c810d..1fd596212bd 100644 --- a/src/vs/platform/windows/test/electron-main/windowsFinder.test.ts +++ b/src/vs/platform/windows/test/electron-main/windowsFinder.test.ts @@ -38,7 +38,7 @@ suite('WindowsFinder', () => { onDidDestroy: Event = Event.None; whenClosedOrLoaded: Promise = Promise.resolve(); id: number = -1; - win: Electron.BrowserWindow = undefined!; + win: Electron.BrowserWindow = null!; config: INativeWindowConfiguration | undefined; openedWorkspace = options.openedFolderUri ? { id: '', uri: options.openedFolderUri } : options.openedWorkspace; backupPath?: string | undefined; From c967932ba34ec52d61d72255425419839c1c4996 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru Date: Tue, 16 Feb 2021 11:50:05 +0100 Subject: [PATCH 190/325] Specify sourceScanPath --- build/azure-pipelines/product-compile.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/build/azure-pipelines/product-compile.yml b/build/azure-pipelines/product-compile.yml index 4f2024a6209..05da3cd45e0 100644 --- a/build/azure-pipelines/product-compile.yml +++ b/build/azure-pipelines/product-compile.yml @@ -140,4 +140,5 @@ steps: - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 displayName: "Component Detection" + sourceScanPath: $(Build.SourcesDirectory) continueOnError: true From 58a427566b6851734346b6ae10499e3df0b1088f Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru Date: Tue, 16 Feb 2021 11:57:14 +0100 Subject: [PATCH 191/325] Revert change --- build/azure-pipelines/product-compile.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/build/azure-pipelines/product-compile.yml b/build/azure-pipelines/product-compile.yml index 05da3cd45e0..4f2024a6209 100644 --- a/build/azure-pipelines/product-compile.yml +++ b/build/azure-pipelines/product-compile.yml @@ -140,5 +140,4 @@ steps: - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 displayName: "Component Detection" - sourceScanPath: $(Build.SourcesDirectory) continueOnError: true From 77493b59a55b557c47fdd653f8eeee65ee6cdb17 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 16 Feb 2021 11:57:55 +0100 Subject: [PATCH 192/325] storage - test all storages closed when shutdown --- .../electron-main/storageMainService.ts | 2 -- .../electron-main/storageMainService.test.ts | 24 ++++++++++++------- .../electron-browser/desktop.main.ts | 2 +- .../electron-sandbox/desktop.main.ts | 2 +- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/vs/platform/storage/electron-main/storageMainService.ts b/src/vs/platform/storage/electron-main/storageMainService.ts index 6b50b94256a..a82e8efd0a8 100644 --- a/src/vs/platform/storage/electron-main/storageMainService.ts +++ b/src/vs/platform/storage/electron-main/storageMainService.ts @@ -69,8 +69,6 @@ export class StorageMainService extends Disposable implements IStorageMainServic if (this.enableMainWorkspaceStorage()) { this._register(this.lifecycleMainService.onWillLoadWindow(async e => { if (e.workspace) { - await this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen); - this.workspaceStorage(e.workspace).initialize(); } })); diff --git a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts index 3aa295edca7..4ed240e033b 100644 --- a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts +++ b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts @@ -146,22 +146,30 @@ suite('StorageMainService (native)', function () { const workspace = { id: generateUuid() }; const storageMainService = new TestStorageMainService(new NullLogService(), new NativeEnvironmentService(parseArgs(process.argv, OPTIONS)), lifecycleMainService, new TestConfigurationService()); - let storage = storageMainService.workspaceStorage(workspace); - let didCloseStorage = false; - storage.onDidCloseStorage(() => { - didCloseStorage = true; + let workspaceStorage = storageMainService.workspaceStorage(workspace); + let didCloseWorkspaceStorage = false; + workspaceStorage.onDidCloseStorage(() => { + didCloseWorkspaceStorage = true; }); - strictEqual(storage, storageMainService.workspaceStorage(workspace)); // same instance as long as not closed + let globalStorage = storageMainService.globalStorage; + let didCloseGlobalStorage = false; + globalStorage.onDidCloseStorage(() => { + didCloseGlobalStorage = true; + }); - await storage.initialize(); + strictEqual(workspaceStorage, storageMainService.workspaceStorage(workspace)); // same instance as long as not closed + + await workspaceStorage.initialize(); await timeout(0); await lifecycleMainService.fireOnWillShutdown(); - strictEqual(didCloseStorage, true); + + strictEqual(didCloseGlobalStorage, true); + strictEqual(didCloseWorkspaceStorage, true); let storage2 = storageMainService.workspaceStorage(workspace); - notStrictEqual(storage, storage2); + notStrictEqual(workspaceStorage, storage2); return storage2.close(); }); diff --git a/src/vs/workbench/electron-browser/desktop.main.ts b/src/vs/workbench/electron-browser/desktop.main.ts index 057696c9420..103816e95c0 100644 --- a/src/vs/workbench/electron-browser/desktop.main.ts +++ b/src/vs/workbench/electron-browser/desktop.main.ts @@ -137,8 +137,8 @@ class DesktopMain extends Disposable { private registerListeners(workbench: Workbench, storageService: NativeStorageService | NativeStorageService2): void { // Workbench Lifecycle - this._register(workbench.onShutdown(() => this.dispose())); this._register(workbench.onWillShutdown(event => event.join(storageService.close(), 'join.closeStorage'))); + this._register(workbench.onShutdown(() => this.dispose())); } private async initServices(): Promise<{ serviceCollection: ServiceCollection, logService: ILogService, storageService: NativeStorageService | NativeStorageService2 }> { diff --git a/src/vs/workbench/electron-sandbox/desktop.main.ts b/src/vs/workbench/electron-sandbox/desktop.main.ts index 14d55ac5c31..709c3ab30c1 100644 --- a/src/vs/workbench/electron-sandbox/desktop.main.ts +++ b/src/vs/workbench/electron-sandbox/desktop.main.ts @@ -120,8 +120,8 @@ class DesktopMain extends Disposable { private registerListeners(workbench: Workbench, storageService: NativeStorageService2): void { // Workbench Lifecycle - this._register(workbench.onShutdown(() => this.dispose())); this._register(workbench.onWillShutdown(event => event.join(storageService.close(), 'join.closeStorage'))); + this._register(workbench.onShutdown(() => this.dispose())); } private async initServices(): Promise<{ serviceCollection: ServiceCollection, logService: ILogService, storageService: NativeStorageService2 }> { From 38ae92f4b19a9d22c79bdaf148dddb59de646115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Tue, 16 Feb 2021 11:59:20 +0100 Subject: [PATCH 193/325] remove unused ui tests --- test/ui/splitview/package.json | 13 - test/ui/splitview/public/index.html | 260 - test/ui/splitview/server.js | 19 - test/ui/splitview/yarn.lock | 341 - test/ui/tree/package.json | 13 - test/ui/tree/public/compressed.json | 15620 -------------------------- test/ui/tree/public/index.html | 403 - test/ui/tree/server.js | 68 - test/ui/tree/tree.js | 24 - test/ui/tree/yarn.lock | 341 - 10 files changed, 17102 deletions(-) delete mode 100644 test/ui/splitview/package.json delete mode 100644 test/ui/splitview/public/index.html delete mode 100644 test/ui/splitview/server.js delete mode 100644 test/ui/splitview/yarn.lock delete mode 100644 test/ui/tree/package.json delete mode 100644 test/ui/tree/public/compressed.json delete mode 100644 test/ui/tree/public/index.html delete mode 100644 test/ui/tree/server.js delete mode 100644 test/ui/tree/tree.js delete mode 100644 test/ui/tree/yarn.lock diff --git a/test/ui/splitview/package.json b/test/ui/splitview/package.json deleted file mode 100644 index d6ce0c37374..00000000000 --- a/test/ui/splitview/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "splitview", - "version": "1.0.0", - "main": "index.js", - "license": "MIT", - "devDependencies": { - "koa": "^2.5.1", - "koa-mount": "^3.0.0", - "koa-route": "^3.2.0", - "koa-static": "^5.0.0", - "mz": "^2.7.0" - } -} \ No newline at end of file diff --git a/test/ui/splitview/public/index.html b/test/ui/splitview/public/index.html deleted file mode 100644 index 0951af8ea52..00000000000 --- a/test/ui/splitview/public/index.html +++ /dev/null @@ -1,260 +0,0 @@ - - - - - Splitview - - - - -
-
- - - - - - diff --git a/test/ui/splitview/server.js b/test/ui/splitview/server.js deleted file mode 100644 index 67f25363671..00000000000 --- a/test/ui/splitview/server.js +++ /dev/null @@ -1,19 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -const fs = require('mz/fs'); -const path = require('path'); -const Koa = require('koa'); -const _ = require('koa-route'); -const serve = require('koa-static'); -const mount = require('koa-mount'); - -const app = new Koa(); - -app.use(serve('public')); -app.use(mount('/static', serve('../../out'))); - -app.listen(3000); -console.log('http://localhost:3000'); \ No newline at end of file diff --git a/test/ui/splitview/yarn.lock b/test/ui/splitview/yarn.lock deleted file mode 100644 index 237201a684e..00000000000 --- a/test/ui/splitview/yarn.lock +++ /dev/null @@ -1,341 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -accepts@^1.2.2: - version "1.3.5" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" - integrity sha1-63d99gEXI6OxTopywIBcjoZ0a9I= - dependencies: - mime-types "~2.1.18" - negotiator "0.6.1" - -any-promise@^1.0.0, any-promise@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" - integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= - -content-disposition@~0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" - integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= - -content-type@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== - -cookies@~0.7.0: - version "0.7.1" - resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.7.1.tgz#7c8a615f5481c61ab9f16c833731bcb8f663b99b" - integrity sha1-fIphX1SBxhq58WyDNzG8uPZjuZs= - dependencies: - depd "~1.1.1" - keygrip "~1.0.2" - -debug@*, debug@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - -debug@^2.6.1: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -deep-equal@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" - integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU= - -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= - -depd@^1.1.0, depd@~1.1.1, depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - -destroy@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - -error-inject@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/error-inject/-/error-inject-1.0.0.tgz#e2b3d91b54aed672f309d950d154850fa11d4f37" - integrity sha1-4rPZG1Su1nLzCdlQ0VSFD6EdTzc= - -escape-html@~1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= - -fresh@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= - -http-assert@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.3.0.tgz#a31a5cf88c873ecbb5796907d4d6f132e8c01e4a" - integrity sha1-oxpc+IyHPsu1eWkH1NbxMujAHko= - dependencies: - deep-equal "~1.0.1" - http-errors "~1.6.1" - -http-errors@^1.2.8, http-errors@^1.6.3, http-errors@~1.6.1, http-errors@~1.6.2: - version "1.6.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" - integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.0" - statuses ">= 1.4.0 < 2" - -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - -is-generator-function@^1.0.3: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522" - integrity sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw== - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= - -keygrip@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.2.tgz#ad3297c557069dea8bcfe7a4fa491b75c5ddeb91" - integrity sha1-rTKXxVcGneqLz+ek+kkbdcXd65E= - -koa-compose@^3.0.0, koa-compose@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-3.2.1.tgz#a85ccb40b7d986d8e5a345b3a1ace8eabcf54de7" - integrity sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec= - dependencies: - any-promise "^1.1.0" - -koa-compose@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877" - integrity sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw== - -koa-convert@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-1.2.0.tgz#da40875df49de0539098d1700b50820cebcd21d0" - integrity sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA= - dependencies: - co "^4.6.0" - koa-compose "^3.0.0" - -koa-is-json@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14" - integrity sha1-JzwH7c3Ljfaiwat9We52SRRR7BQ= - -koa-mount@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/koa-mount/-/koa-mount-3.0.0.tgz#08cab3b83d31442ed8b7e75c54b1abeb922ec197" - integrity sha1-CMqzuD0xRC7Yt+dcVLGr65IuwZc= - dependencies: - debug "^2.6.1" - koa-compose "^3.2.1" - -koa-route@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/koa-route/-/koa-route-3.2.0.tgz#76298b99a6bcfa9e38cab6fe5c79a8733e758bce" - integrity sha1-dimLmaa8+p44yrb+XHmocz51i84= - dependencies: - debug "*" - methods "~1.1.0" - path-to-regexp "^1.2.0" - -koa-send@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-5.0.0.tgz#5e8441e07ef55737734d7ced25b842e50646e7eb" - integrity sha512-90ZotV7t0p3uN9sRwW2D484rAaKIsD8tAVtypw/aBU+ryfV+fR2xrcAwhI8Wl6WRkojLUs/cB9SBSCuIb+IanQ== - dependencies: - debug "^3.1.0" - http-errors "^1.6.3" - mz "^2.7.0" - resolve-path "^1.4.0" - -koa-static@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/koa-static/-/koa-static-5.0.0.tgz#5e92fc96b537ad5219f425319c95b64772776943" - integrity sha512-UqyYyH5YEXaJrf9S8E23GoJFQZXkBVJ9zYYMPGz919MSX1KuvAcycIuS0ci150HCoPf4XQVhQ84Qf8xRPWxFaQ== - dependencies: - debug "^3.1.0" - koa-send "^5.0.0" - -koa@^2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/koa/-/koa-2.5.1.tgz#79f8b95f8d72d04fe9a58a8da5ebd6d341103f9c" - integrity sha512-cchwbMeG2dv3E2xTAmheDAuvR53tPgJZN/Hf1h7bTzJLSPcFZp8/t5+bNKJ6GaQZoydhZQ+1GNruhKdj3lIrug== - dependencies: - accepts "^1.2.2" - content-disposition "~0.5.0" - content-type "^1.0.0" - cookies "~0.7.0" - debug "*" - delegates "^1.0.0" - depd "^1.1.0" - destroy "^1.0.3" - error-inject "~1.0.0" - escape-html "~1.0.1" - fresh "^0.5.2" - http-assert "^1.1.0" - http-errors "^1.2.8" - is-generator-function "^1.0.3" - koa-compose "^4.0.0" - koa-convert "^1.2.0" - koa-is-json "^1.0.0" - mime-types "^2.0.7" - on-finished "^2.1.0" - only "0.0.2" - parseurl "^1.3.0" - statuses "^1.2.0" - type-is "^1.5.5" - vary "^1.0.0" - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= - -methods@~1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= - -mime-db@~1.33.0: - version "1.33.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" - integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ== - -mime-types@^2.0.7, mime-types@~2.1.18: - version "2.1.18" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" - integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ== - dependencies: - mime-db "~1.33.0" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -mz@^2.7.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" - integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== - dependencies: - any-promise "^1.0.0" - object-assign "^4.0.1" - thenify-all "^1.0.0" - -negotiator@0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" - integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= - -object-assign@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -on-finished@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= - dependencies: - ee-first "1.1.1" - -only@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" - integrity sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q= - -parseurl@^1.3.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" - integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M= - -path-is-absolute@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-to-regexp@^1.2.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" - integrity sha1-Wf3g9DW62suhA6hOnTvGTpa5k30= - dependencies: - isarray "0.0.1" - -resolve-path@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/resolve-path/-/resolve-path-1.4.0.tgz#c4bda9f5efb2fce65247873ab36bb4d834fe16f7" - integrity sha1-xL2p9e+y/OZSR4c6s2u02DT+Fvc= - dependencies: - http-errors "~1.6.2" - path-is-absolute "1.0.1" - -setprototypeof@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" - integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== - -"statuses@>= 1.4.0 < 2", statuses@^1.2.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - -thenify-all@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" - integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= - dependencies: - thenify ">= 3.1.0 < 4" - -"thenify@>= 3.1.0 < 4": - version "3.3.0" - resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.0.tgz#e69e38a1babe969b0108207978b9f62b88604839" - integrity sha1-5p44obq+lpsBCCB5eLn2K4hgSDk= - dependencies: - any-promise "^1.0.0" - -type-is@^1.5.5: - version "1.6.16" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" - integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.18" - -vary@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= diff --git a/test/ui/tree/package.json b/test/ui/tree/package.json deleted file mode 100644 index 1a3b32d627d..00000000000 --- a/test/ui/tree/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "tree", - "version": "1.0.0", - "main": "index.js", - "license": "MIT", - "devDependencies": { - "koa": "^2.5.1", - "koa-mount": "^3.0.0", - "koa-route": "^3.2.0", - "koa-static": "^5.0.0", - "mz": "^2.7.0" - } -} \ No newline at end of file diff --git a/test/ui/tree/public/compressed.json b/test/ui/tree/public/compressed.json deleted file mode 100644 index 939a0a29145..00000000000 --- a/test/ui/tree/public/compressed.json +++ /dev/null @@ -1,15620 +0,0 @@ -[ - { - "element": { - "name": "eclipse.platform.debug" - }, - "children": [ - { - "element": { - "name": ".git" - }, - "children": [ - { - "element": { - "name": "HEAD" - }, - "incompressible": true - }, - { - "element": { - "name": "branches" - }, - "children": [] - }, - { - "element": { - "name": "config" - }, - "incompressible": true - }, - { - "element": { - "name": "description" - }, - "incompressible": true - }, - { - "element": { - "name": "hooks" - }, - "children": [ - { - "element": { - "name": "applypatch-msg.sample" - }, - "incompressible": true - }, - { - "element": { - "name": "commit-msg.sample" - }, - "incompressible": true - }, - { - "element": { - "name": "fsmonitor-watchman.sample" - }, - "incompressible": true - }, - { - "element": { - "name": "post-update.sample" - }, - "incompressible": true - }, - { - "element": { - "name": "pre-applypatch.sample" - }, - "incompressible": true - }, - { - "element": { - "name": "pre-commit.sample" - }, - "incompressible": true - }, - { - "element": { - "name": "pre-push.sample" - }, - "incompressible": true - }, - { - "element": { - "name": "pre-rebase.sample" - }, - "incompressible": true - }, - { - "element": { - "name": "pre-receive.sample" - }, - "incompressible": true - }, - { - "element": { - "name": "prepare-commit-msg.sample" - }, - "incompressible": true - }, - { - "element": { - "name": "update.sample" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "index" - }, - "incompressible": true - }, - { - "element": { - "name": "info" - }, - "children": [ - { - "element": { - "name": "exclude" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "logs" - }, - "children": [ - { - "element": { - "name": "HEAD" - }, - "incompressible": true - }, - { - "element": { - "name": "refs" - }, - "children": [ - { - "element": { - "name": "heads" - }, - "children": [ - { - "element": { - "name": "main" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "remotes" - }, - "children": [ - { - "element": { - "name": "origin" - }, - "children": [ - { - "element": { - "name": "HEAD" - }, - "incompressible": true - } - ] - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "objects" - }, - "children": [ - { - "element": { - "name": "info" - }, - "children": [] - }, - { - "element": { - "name": "pack" - }, - "children": [ - { - "element": { - "name": "pack-2b1503bd0b85396d8596e9e99d956bfc3fbe497b.idx" - }, - "incompressible": true - }, - { - "element": { - "name": "pack-2b1503bd0b85396d8596e9e99d956bfc3fbe497b.pack" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "packed-refs" - }, - "incompressible": true - }, - { - "element": { - "name": "refs" - }, - "children": [ - { - "element": { - "name": "heads" - }, - "children": [ - { - "element": { - "name": "main" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "remotes" - }, - "children": [ - { - "element": { - "name": "origin" - }, - "children": [ - { - "element": { - "name": "HEAD" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "tags" - }, - "children": [ - { - "element": { - "name": "I20190722-1800" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "shallow" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": ".gitignore" - }, - "incompressible": true - }, - { - "element": { - "name": "CONTRIBUTING" - }, - "incompressible": true - }, - { - "element": { - "name": "LICENSE" - }, - "incompressible": true - }, - { - "element": { - "name": "NOTICE" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.core.externaltools" - }, - "children": [ - { - "element": { - "name": ".classpath" - }, - "incompressible": true - }, - { - "element": { - "name": ".project" - }, - "incompressible": true - }, - { - "element": { - "name": ".settings" - }, - "children": [ - { - "element": { - "name": "org.eclipse.core.resources.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.core.runtime.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.core.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.ui.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.pde.api.tools.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.pde.prefs" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "META-INF" - }, - "children": [ - { - "element": { - "name": "MANIFEST.MF" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "about.html" - }, - "incompressible": true - }, - { - "element": { - "name": "build.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "plugin.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "plugin.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "pom.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "src" - }, - "children": [ - { - "element": { - "name": "org" - }, - "children": [ - { - "element": { - "name": "eclipse" - }, - "children": [ - { - "element": { - "name": "core" - }, - "children": [ - { - "element": { - "name": "externaltools" - }, - "children": [ - { - "element": { - "name": "internal" - }, - "children": [ - { - "element": { - "name": "ExternalToolsCore.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IExternalToolConstants.java" - }, - "incompressible": true - }, - { - "element": { - "name": "launchConfigurations" - }, - "children": [ - { - "element": { - "name": "BackgroundResourceRefresher.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolsCoreUtil.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolsProgramMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolsProgramMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "ProgramLaunchDelegate.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "model" - }, - "children": [ - { - "element": { - "name": "BuilderCoreUtils.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolBuilder.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolsModelMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolsModelMessages.properties" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "registry" - }, - "children": [ - { - "element": { - "name": "ExternalToolMigration.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolsMigrationMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolsMigrationMessages.properties" - }, - "incompressible": true - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "org.eclipse.core.variables" - }, - "children": [ - { - "element": { - "name": ".classpath" - }, - "incompressible": true - }, - { - "element": { - "name": ".project" - }, - "incompressible": true - }, - { - "element": { - "name": ".settings" - }, - "children": [ - { - "element": { - "name": "org.eclipse.core.resources.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.core.runtime.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.core.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.ui.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.pde.api.tools.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.pde.prefs" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "META-INF" - }, - "children": [ - { - "element": { - "name": "MANIFEST.MF" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "about.html" - }, - "incompressible": true - }, - { - "element": { - "name": "build.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "plugin.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "plugin.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "pom.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "schema" - }, - "children": [ - { - "element": { - "name": "dynamicVariables.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "valueVariables.exsd" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "src" - }, - "children": [ - { - "element": { - "name": "org" - }, - "children": [ - { - "element": { - "name": "eclipse" - }, - "children": [ - { - "element": { - "name": "core" - }, - "children": [ - { - "element": { - "name": "internal" - }, - "children": [ - { - "element": { - "name": "variables" - }, - "children": [ - { - "element": { - "name": "ContributedValueVariable.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DynamicVariable.java" - }, - "incompressible": true - }, - { - "element": { - "name": "EclipseHomeVariableResolver.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StringSubstitutionEngine.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StringVariable.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StringVariableManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ValueVariable.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VariablesMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VariablesMessages.properties" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "variables" - }, - "children": [ - { - "element": { - "name": "IDynamicVariable.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDynamicVariableResolver.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IStringVariable.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IStringVariableManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IValueVariable.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IValueVariableInitializer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IValueVariableListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VariablesPlugin.java" - }, - "incompressible": true - }, - { - "element": { - "name": "package.html" - }, - "incompressible": true - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "org.eclipse.debug.core" - }, - "children": [ - { - "element": { - "name": ".classpath" - }, - "incompressible": true - }, - { - "element": { - "name": ".options" - }, - "incompressible": true - }, - { - "element": { - "name": ".project" - }, - "incompressible": true - }, - { - "element": { - "name": ".settings" - }, - "children": [ - { - "element": { - "name": "org.eclipse.core.resources.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.core.runtime.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.core.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.ui.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.pde.api.tools.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.pde.prefs" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "META-INF" - }, - "children": [ - { - "element": { - "name": "MANIFEST.MF" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "about.html" - }, - "incompressible": true - }, - { - "element": { - "name": "build.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "core" - }, - "children": [ - { - "element": { - "name": "org" - }, - "children": [ - { - "element": { - "name": "eclipse" - }, - "children": [ - { - "element": { - "name": "debug" - }, - "children": [ - { - "element": { - "name": "core" - }, - "children": [ - { - "element": { - "name": "DebugEvent.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugException.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugPlugin.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IBreakpointListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IBreakpointManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IBreakpointManagerListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IBreakpointsListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDebugEventFilter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDebugEventSetListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IExpressionListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IExpressionManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IExpressionsListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunch.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchConfiguration.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchConfigurationListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchConfigurationMigrationDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchConfigurationType.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchConfigurationWorkingCopy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchMode.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchesListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchesListener2.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILogicalStructureProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILogicalStructureType.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMemoryBlockListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMemoryBlockManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IProcessFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IPrototypeAttributesLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IRequest.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IStatusHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IStreamListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "Launch.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RefreshUtil.java" - }, - "incompressible": true - }, - { - "element": { - "name": "commands" - }, - "children": [ - { - "element": { - "name": "AbstractDebugCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDebugCommandHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDebugCommandRequest.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDisconnectHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDropToFrameHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IEnabledStateRequest.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IRestartHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IResumeHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IStepFiltersHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IStepIntoHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IStepOverHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IStepReturnHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ISuspendHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ITerminateHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "package.html" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "model" - }, - "children": [ - { - "element": { - "name": "Breakpoint.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugElement.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IBreakpoint.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IBreakpointImportParticipant.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDebugElement.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDebugModelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDebugTarget.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDisconnect.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDropToFrame.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IErrorReportingExpression.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IExpression.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IFilteredStep.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IFlushableStreamMonitor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IIndexedValue.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchConfigurationDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchConfigurationDelegate2.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILineBreakpoint.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILogicalStructureTypeDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILogicalStructureTypeDelegate2.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMemoryBlock.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMemoryBlockExtension.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMemoryBlockRetrieval.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMemoryBlockRetrievalExtension.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IPersistableSourceLocator.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IProcess.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IRegister.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IRegisterGroup.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ISourceLocator.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IStackFrame.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IStep.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IStepFilter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IStepFilters.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IStreamMonitor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IStreamsProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IStreamsProxy2.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ISuspendResume.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ITerminate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IThread.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ITriggerPoint.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IValue.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IValueModification.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IVariable.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IWatchExpression.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IWatchExpressionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IWatchExpressionListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IWatchExpressionResult.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IWatchpoint.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LineBreakpoint.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryByte.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RuntimeProcess.java" - }, - "incompressible": true - }, - { - "element": { - "name": "package.html" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "package.html" - }, - "incompressible": true - }, - { - "element": { - "name": "sourcelookup" - }, - "children": [ - { - "element": { - "name": "AbstractSourceLookupDirector.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AbstractSourceLookupParticipant.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IPersistableSourceLocator2.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ISourceContainer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ISourceContainerType.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ISourceContainerTypeDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ISourceLookupDirector.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ISourceLookupParticipant.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ISourcePathComputer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ISourcePathComputerDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "containers" - }, - "children": [ - { - "element": { - "name": "AbstractSourceContainer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AbstractSourceContainerTypeDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ArchiveSourceContainer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CompositeSourceContainer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ContainerSourceContainer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DefaultSourceContainer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DirectorySourceContainer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalArchiveSourceContainer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "FolderSourceContainer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LocalFileStorage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProjectSourceContainer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WorkspaceSourceContainer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ZipEntryStorage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "package.html" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "package.html" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "internal" - }, - "children": [ - { - "element": { - "name": "core" - }, - "children": [ - { - "element": { - "name": "BreakpointImportParticipantDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugCoreMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugCoreMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugOptions.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugPreferenceInitializer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "EnvironmentVariableResolver.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExpressionManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IConfigurationElementConstants.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IExpressionsListener2.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IInternalDebugCoreConstants.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMementoConstants.java" - }, - "incompressible": true - }, - { - "element": { - "name": "InputStreamMonitor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfiguration.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationComparator.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationInfo.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationType.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationWorkingCopy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchMode.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchablePropertyTester.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LogicalStructureManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LogicalStructureProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LogicalStructureType.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryBlockManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "NullStreamsProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "OutputStreamMonitor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "Preferences.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PreferredDelegateModifyListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RefreshScopeComparator.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ResourceFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StepFilter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StepFilterManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StreamsProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SystemPropertyResolver.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SystemVariableResolver.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WatchExpression.java" - }, - "incompressible": true - }, - { - "element": { - "name": "XMLMemento.java" - }, - "incompressible": true - }, - { - "element": { - "name": "commands" - }, - "children": [ - { - "element": { - "name": "CommandAdapterFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugCommandRequest.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DisconnectCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DropToFrameCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ForEachCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "Request.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ResumeCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StepCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StepFiltersCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StepIntoCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StepOverCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StepReturnCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SuspendCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TerminateCommand.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "groups" - }, - "children": [ - { - "element": { - "name": "GroupLaunch.java" - }, - "incompressible": true - }, - { - "element": { - "name": "GroupLaunchConfigurationDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "GroupLaunchElement.java" - }, - "incompressible": true - }, - { - "element": { - "name": "GroupMemberChangeListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "observer" - }, - "children": [ - { - "element": { - "name": "ProcessObserver.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StreamObserver.java" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "sourcelookup" - }, - "children": [ - { - "element": { - "name": "SourceContainerType.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceLocatorMementoComparator.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceLookupMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceLookupMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceLookupUtils.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourcePathComputer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "containers" - }, - "children": [ - { - "element": { - "name": "ArchiveSourceContainerType.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DefaultSourceContainerType.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DirectorySourceContainerType.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalArchiveSourceContainerType.java" - }, - "incompressible": true - }, - { - "element": { - "name": "FolderSourceContainerType.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProjectSourceContainerType.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WorkspaceSourceContainerType.java" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "variables" - }, - "children": [ - { - "element": { - "name": "ContainerResolver.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DateTimeResolver.java" - }, - "incompressible": true - }, - { - "element": { - "name": "Messages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "Messages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "ProjectResolver.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ResourceResolver.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WorkspaceResolver.java" - }, - "incompressible": true - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "plugin.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "plugin.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "pom.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "schema" - }, - "children": [ - { - "element": { - "name": "breakpointImportParticipants.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "breakpoints.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "launchConfigurationComparators.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "launchConfigurationTypes.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "launchDelegates.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "launchModes.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "launchers.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "logicalStructureProviders.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "logicalStructureTypes.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "processFactories.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "sourceContainerTypes.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "sourceLocators.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "sourcePathComputers.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "statusHandlers.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "stepFilters.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "watchExpressionDelegates.exsd" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "scripts" - }, - "children": [ - { - "element": { - "name": "exportplugin.xml" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "org.eclipse.debug.examples.core" - }, - "children": [ - { - "element": { - "name": ".classpath" - }, - "incompressible": true - }, - { - "element": { - "name": ".project" - }, - "incompressible": true - }, - { - "element": { - "name": ".settings" - }, - "children": [ - { - "element": { - "name": "org.eclipse.core.resources.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.core.runtime.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.core.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.ui.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.pde.api.tools.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.pde.prefs" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "META-INF" - }, - "children": [ - { - "element": { - "name": "MANIFEST.MF" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "OSGI-INF" - }, - "children": [ - { - "element": { - "name": "l10n" - }, - "children": [ - { - "element": { - "name": "bundle.properties" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "about.html" - }, - "incompressible": true - }, - { - "element": { - "name": "build.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "forceQualifierUpdate.txt" - }, - "incompressible": true - }, - { - "element": { - "name": "pdavm" - }, - "children": [ - { - "element": { - "name": "src" - }, - "children": [ - { - "element": { - "name": "org" - }, - "children": [ - { - "element": { - "name": "eclipse" - }, - "children": [ - { - "element": { - "name": "debug" - }, - "children": [ - { - "element": { - "name": "examples" - }, - "children": [ - { - "element": { - "name": "pdavm" - }, - "children": [ - { - "element": { - "name": "PDAVirtualMachine.java" - }, - "incompressible": true - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "tests" - }, - "children": [ - { - "element": { - "name": "vmtest10.pda" - }, - "incompressible": true - }, - { - "element": { - "name": "vmtest2.pda" - }, - "incompressible": true - }, - { - "element": { - "name": "vmtest3.pda" - }, - "incompressible": true - }, - { - "element": { - "name": "vmtest6.pda" - }, - "incompressible": true - }, - { - "element": { - "name": "vmtest8.pda" - }, - "incompressible": true - }, - { - "element": { - "name": "vmtest9.pda" - }, - "incompressible": true - }, - { - "element": { - "name": "vmtest_children.pda" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "plugin.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "pom.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "readme.html" - }, - "incompressible": true - }, - { - "element": { - "name": "samples" - }, - "children": [ - { - "element": { - "name": "counter.pda" - }, - "incompressible": true - }, - { - "element": { - "name": "drop.pda" - }, - "incompressible": true - }, - { - "element": { - "name": "example.pda" - }, - "incompressible": true - }, - { - "element": { - "name": "fibonacci.pda" - }, - "incompressible": true - }, - { - "element": { - "name": "registers.pda" - }, - "incompressible": true - }, - { - "element": { - "name": "stack.pda" - }, - "incompressible": true - }, - { - "element": { - "name": "structures.pda" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "scripts" - }, - "children": [ - { - "element": { - "name": "build.xml" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "src" - }, - "children": [ - { - "element": { - "name": "org" - }, - "children": [ - { - "element": { - "name": "eclipse" - }, - "children": [ - { - "element": { - "name": "debug" - }, - "children": [ - { - "element": { - "name": "examples" - }, - "children": [ - { - "element": { - "name": "core" - }, - "children": [ - { - "element": { - "name": "midi" - }, - "children": [ - { - "element": { - "name": "launcher" - }, - "children": [ - { - "element": { - "name": "ClockControl.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LengthControl.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MidiLaunch.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MidiLaunchDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SequencerControl.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TempoControl.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TimeControl.java" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "pda" - }, - "children": [ - { - "element": { - "name": "DebugCorePlugin.java" - }, - "incompressible": true - }, - { - "element": { - "name": "breakpoints" - }, - "children": [ - { - "element": { - "name": "PDALineBreakpoint.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDARunToLineBreakpoint.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAWatchpoint.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "launcher" - }, - "children": [ - { - "element": { - "name": "PDALaunchDelegate.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "model" - }, - "children": [ - { - "element": { - "name": "IPDAEventListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAArray.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAArrayEntry.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDADebugElement.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDADebugTarget.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAMemoryBlock.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAStackFrame.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAStackValue.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAThread.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAValue.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAVariable.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WordStructureDelegate.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "protocol" - }, - "children": [ - { - "element": { - "name": "PDABitFieldData.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAChildrenCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAClearBreakpointCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDACommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDACommandResult.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDADataCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDADropFrameCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAEvalCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAEvalResultEvent.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAEvent.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAEventStopCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAExitedEvent.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAFrameCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAFrameCommandResult.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAFrameData.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAGroupsCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAListResult.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDANoSuchLabelEvent.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAPopDataCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAPushDataCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDARegisterData.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDARegistersCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDARegistersCommandResult.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDARegistersEvent.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDARestartCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAResumeCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAResumedEvent.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDARunControlEvent.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDASetBreakpointCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDASetDataCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDASetVarCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAStackCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAStackCommandResult.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAStackDepthCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAStackDepthCommandResult.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAStartedEvent.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAStepCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAStepReturnCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDASuspendCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDASuspendedEvent.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDATerminateCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDATerminatedEvent.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAUnimplementedInstructionEvent.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAVMResumeCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAVMResumedEvent.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAVMStartedEvent.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAVMSuspendCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAVMSuspendedEvent.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAVMTerminatedEvent.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAVarCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAWatchCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "package.html" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "sourcelookup" - }, - "children": [ - { - "element": { - "name": "PDASourceLookupDirector.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDASourceLookupParticipant.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDASourcePathComputerDelegate.java" - }, - "incompressible": true - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "src_ant" - }, - "children": [ - { - "element": { - "name": "org" - }, - "children": [ - { - "element": { - "name": "eclipse" - }, - "children": [ - { - "element": { - "name": "debug" - }, - "children": [ - { - "element": { - "name": "examples" - }, - "children": [ - { - "element": { - "name": "ant" - }, - "children": [ - { - "element": { - "name": "tasks" - }, - "children": [ - { - "element": { - "name": "PreProcessor.java" - }, - "incompressible": true - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "org.eclipse.debug.examples.memory" - }, - "children": [ - { - "element": { - "name": ".classpath" - }, - "incompressible": true - }, - { - "element": { - "name": ".project" - }, - "incompressible": true - }, - { - "element": { - "name": ".settings" - }, - "children": [ - { - "element": { - "name": "org.eclipse.core.resources.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.core.runtime.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.core.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.ui.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.pde.api.tools.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.pde.prefs" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "META-INF" - }, - "children": [ - { - "element": { - "name": "MANIFEST.MF" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "build.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "icons" - }, - "children": [ - { - "element": { - "name": "full" - }, - "children": [ - { - "element": { - "name": "obj16" - }, - "children": [ - { - "element": { - "name": "hex_tree.gif" - }, - "incompressible": true - }, - { - "element": { - "name": "launch.gif" - }, - "incompressible": true - }, - { - "element": { - "name": "memory_segment.gif" - }, - "incompressible": true - }, - { - "element": { - "name": "memory_unit.gif" - }, - "incompressible": true - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "plugin.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "plugin.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "pom.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "src" - }, - "children": [ - { - "element": { - "name": "org" - }, - "children": [ - { - "element": { - "name": "eclipse" - }, - "children": [ - { - "element": { - "name": "debug" - }, - "children": [ - { - "element": { - "name": "examples" - }, - "children": [ - { - "element": { - "name": "internal" - }, - "children": [ - { - "element": { - "name": "memory" - }, - "children": [ - { - "element": { - "name": "MemoryViewSamplePlugin.java" - }, - "incompressible": true - }, - { - "element": { - "name": "core" - }, - "children": [ - { - "element": { - "name": "Messages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SampleDebugTarget.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SampleMemoryBlock.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SampleRegister.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SampleRegisterGroup.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SampleStackFrame.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SampleThread.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SampleValue.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SampleVariable.java" - }, - "incompressible": true - }, - { - "element": { - "name": "messages.properties" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "engine" - }, - "children": [ - { - "element": { - "name": "SampleEngine.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SampleMemoryUnit.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "launchconfig" - }, - "children": [ - { - "element": { - "name": "SampleLaunchConfigurationDelegateEx.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SampleLaunchTabGroup.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SampleModelPresentation.java" - }, - "incompressible": true - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "org.eclipse.debug.examples.mixedmode" - }, - "children": [ - { - "element": { - "name": ".classpath" - }, - "incompressible": true - }, - { - "element": { - "name": ".project" - }, - "incompressible": true - }, - { - "element": { - "name": ".settings" - }, - "children": [ - { - "element": { - "name": "org.eclipse.core.resources.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.core.runtime.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.core.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.ui.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.pde.api.tools.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.pde.prefs" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "META-INF" - }, - "children": [ - { - "element": { - "name": "MANIFEST.MF" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "OSGI-INF" - }, - "children": [ - { - "element": { - "name": "l10n" - }, - "children": [ - { - "element": { - "name": "bundle.properties" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "about.html" - }, - "incompressible": true - }, - { - "element": { - "name": "build.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "plugin.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "pom.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "src" - }, - "children": [ - { - "element": { - "name": "org" - }, - "children": [ - { - "element": { - "name": "eclipse" - }, - "children": [ - { - "element": { - "name": "debug" - }, - "children": [ - { - "element": { - "name": "internal" - }, - "children": [ - { - "element": { - "name": "examples" - }, - "children": [ - { - "element": { - "name": "mixedmode" - }, - "children": [ - { - "element": { - "name": "Activator.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AntExtraTab.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ClearPreferredDelegatesHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DoNothingLaunchConfigurationDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DoNothingMainTab.java" - }, - "incompressible": true - }, - { - "element": { - "name": "Messages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "messages.properties" - }, - "incompressible": true - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "org.eclipse.debug.examples.ui" - }, - "children": [ - { - "element": { - "name": ".classpath" - }, - "incompressible": true - }, - { - "element": { - "name": ".project" - }, - "incompressible": true - }, - { - "element": { - "name": ".settings" - }, - "children": [ - { - "element": { - "name": "org.eclipse.core.resources.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.core.runtime.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.core.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.ui.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.pde.api.tools.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.pde.prefs" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "META-INF" - }, - "children": [ - { - "element": { - "name": "MANIFEST.MF" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "OSGI-INF" - }, - "children": [ - { - "element": { - "name": "l10n" - }, - "children": [ - { - "element": { - "name": "bundle.properties" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "about.html" - }, - "incompressible": true - }, - { - "element": { - "name": "build.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "icons" - }, - "children": [ - { - "element": { - "name": "full" - }, - "children": [ - { - "element": { - "name": "dlcl16" - }, - "children": [ - { - "element": { - "name": "pop.gif" - }, - "incompressible": true - }, - { - "element": { - "name": "push.gif" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "elcl16" - }, - "children": [ - { - "element": { - "name": "pop.gif" - }, - "incompressible": true - }, - { - "element": { - "name": "push.gif" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "obj16" - }, - "children": [ - { - "element": { - "name": "clef.png" - }, - "incompressible": true - }, - { - "element": { - "name": "note.gif" - }, - "incompressible": true - }, - { - "element": { - "name": "pda.gif" - }, - "incompressible": true - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "plugin.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "pom.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "src" - }, - "children": [ - { - "element": { - "name": "org" - }, - "children": [ - { - "element": { - "name": "eclipse" - }, - "children": [ - { - "element": { - "name": "debug" - }, - "children": [ - { - "element": { - "name": "examples" - }, - "children": [ - { - "element": { - "name": "ui" - }, - "children": [ - { - "element": { - "name": "midi" - }, - "children": [ - { - "element": { - "name": "adapters" - }, - "children": [ - { - "element": { - "name": "CheckboxModelProxyFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ControlCellModifier.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ControlEditor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ControlEventHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ControlLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ControlsMementoProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MidiAdapterFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MidiEventLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MidiEventModelProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MidiStepOverHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SequencerColumnFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SequencerColumnPresentation.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SequencerContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SequencerControlsModelProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SequencerModelProxyFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TrackColumnFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TrackColumnPresentation.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TrackContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TrackLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TrackModelProxy.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "detailpanes" - }, - "children": [ - { - "element": { - "name": "ClockSliderDetailPane.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ControlDetailPaneFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TempoSliderDetailPane.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "launcher" - }, - "children": [ - { - "element": { - "name": "ExampleLaunchStatusHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MidiLaunchShortcut.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MidiMainTab.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MidiTabGroup.java" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "pda" - }, - "children": [ - { - "element": { - "name": "DebugUIPlugin.java" - }, - "incompressible": true - }, - { - "element": { - "name": "adapters" - }, - "children": [ - { - "element": { - "name": "AdapterFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AddPDAMemoryBlockAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CommandAdapterFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ModelProxyFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDADebugTargetContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDADebugTargetProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDARestartDebugCommand.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAThreadEventHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAViewActionProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAVirtualFindAction.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "breakpoints" - }, - "children": [ - { - "element": { - "name": "PDABreakpointAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAEditorAdapterFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDARunToLineAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAToggleWatchpointsTarget.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAToggleWatchpointsTargetFactory.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "editor" - }, - "children": [ - { - "element": { - "name": "AnnotationHover.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAContentAssistProcessor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAContentAssistant.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAEditor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAEditorMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAScanner.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDASourceViewerConfiguration.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PopFrameActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TextHover.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WordFinder.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "launcher" - }, - "children": [ - { - "element": { - "name": "PDALaunchShortcut.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDAMainTab.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PDATabGroup.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "presentation" - }, - "children": [ - { - "element": { - "name": "PDAModelPresentation.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "views" - }, - "children": [ - { - "element": { - "name": "AbstractDataStackViewHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CanPushTester.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CheckboxView.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DataStackView.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PopHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PushHandler.java" - }, - "incompressible": true - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "org.eclipse.debug.tests" - }, - "children": [ - { - "element": { - "name": ".classpath" - }, - "incompressible": true - }, - { - "element": { - "name": ".project" - }, - "incompressible": true - }, - { - "element": { - "name": ".settings" - }, - "children": [ - { - "element": { - "name": "org.eclipse.core.resources.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.core.runtime.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.core.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.ui.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.pde.prefs" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "META-INF" - }, - "children": [ - { - "element": { - "name": "MANIFEST.MF" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "Platform Debug Test Suite.launch" - }, - "incompressible": true - }, - { - "element": { - "name": "about.html" - }, - "incompressible": true - }, - { - "element": { - "name": "build.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "forceQualifierUpdate.txt" - }, - "incompressible": true - }, - { - "element": { - "name": "icons" - }, - "children": [ - { - "element": { - "name": "image1.gif" - }, - "incompressible": true - }, - { - "element": { - "name": "image2.gif" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "plugin.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "plugin.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "pom.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "src" - }, - "children": [ - { - "element": { - "name": "org" - }, - "children": [ - { - "element": { - "name": "eclipse" - }, - "children": [ - { - "element": { - "name": "debug" - }, - "children": [ - { - "element": { - "name": "tests" - }, - "children": [ - { - "element": { - "name": "AbstractDebugTest.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AutomatedSuite.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LocalSuite.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PerformanceSuite.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TestUtil.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TestsPlugin.java" - }, - "incompressible": true - }, - { - "element": { - "name": "breakpoint" - }, - "children": [ - { - "element": { - "name": "BreakpointOrderingTests.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "console" - }, - "children": [ - { - "element": { - "name": "ConsoleDocumentAdapterTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleManagerTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IOConsoleTestUtil.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IOConsoleTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MockProcess.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProcessConsoleManagerTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProcessConsoleTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StreamsProxyTests.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "expressions" - }, - "children": [ - { - "element": { - "name": "ExpressionManagerTests.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "launching" - }, - "children": [ - { - "element": { - "name": "AbstractLaunchTest.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AcceleratorSubstitutionTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ArgumentParsingTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ArgumentsPrinter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CancellingLaunchDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugFileStore.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugFileSystem.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchFavoriteTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchGroupTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchHistoryTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchManagerTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RefreshTabTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TestLaunchDelegate.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "sourcelookup" - }, - "children": [ - { - "element": { - "name": "SourceLookupFacilityTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TestLaunch.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TestSourceDirector.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TestSourceLocator.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TestStackFrame.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "statushandlers" - }, - "children": [ - { - "element": { - "name": "StatusHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StatusHandlerTests.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "stepfilters" - }, - "children": [ - { - "element": { - "name": "StepFiltersTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TestStepFilter.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "view" - }, - "children": [ - { - "element": { - "name": "memory" - }, - "children": [ - { - "element": { - "name": "DynamicRenderingBindings.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryBlock.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryBlockDynamic.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryBlockOne.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryBlockThree.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryBlockTwo.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryRenderingTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RenderingTypeDelegate.java" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "viewer" - }, - "children": [ - { - "element": { - "name": "model" - }, - "children": [ - { - "element": { - "name": "AbstractViewerModelTest.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CheckTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ChildrenUpdateTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ColumnPresentationTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ContentTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DeltaTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "FilterTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "FilterTransformTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ITestModelUpdatesListenerConstants.java" - }, - "incompressible": true - }, - { - "element": { - "name": "JFaceViewerCheckTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "JFaceViewerContentTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "JFaceViewerDeltaTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "JFaceViewerFilterTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "JFaceViewerLazyTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "JFaceViewerPerformanceTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "JFaceViewerPopupTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "JFaceViewerSelectionTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "JFaceViewerStateTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "JFaceViewerTopIndexTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "JFaceViewerUpdateTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LazyTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PerformanceTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PopupTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PresentationContextTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SelectionTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StateTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TestModel.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TestModelUpdatesListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TreeModelViewerAutopopulateAgent.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TreePathWrapper.java" - }, - "incompressible": true - }, - { - "element": { - "name": "UpdateTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VirtualViewerContentTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VirtualViewerDeltaTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VirtualViewerFilterTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VirtualViewerLazyModeTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VirtualViewerPerformanceTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VirtualViewerPopupTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VirtualViewerSelectionTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VirtualViewerStateTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VirtualViewerUpdateTests.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VisibleVirtualItemValidator.java" - }, - "incompressible": true - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "test-import" - }, - "children": [ - { - "element": { - "name": "Import1.launch" - }, - "incompressible": true - }, - { - "element": { - "name": "Import2.launch" - }, - "incompressible": true - }, - { - "element": { - "name": "Import3.launch" - }, - "incompressible": true - }, - { - "element": { - "name": "Import4.launch" - }, - "incompressible": true - }, - { - "element": { - "name": "Import5.launch" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "test.xml" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "org.eclipse.debug.ui" - }, - "children": [ - { - "element": { - "name": ".classpath" - }, - "incompressible": true - }, - { - "element": { - "name": ".options" - }, - "incompressible": true - }, - { - "element": { - "name": ".project" - }, - "incompressible": true - }, - { - "element": { - "name": ".settings" - }, - "children": [ - { - "element": { - "name": ".api_filters" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.core.resources.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.core.runtime.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.core.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.ui.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.pde.api.tools.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.pde.prefs" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "META-INF" - }, - "children": [ - { - "element": { - "name": "MANIFEST.MF" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "about.html" - }, - "incompressible": true - }, - { - "element": { - "name": "build.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "css" - }, - "children": [ - { - "element": { - "name": "e4-dark_debug_prefstyle.css" - }, - "incompressible": true - }, - { - "element": { - "name": "e4-light_debug_prefstyle.css" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "forceQualifierUpdate.txt" - }, - "incompressible": true - }, - { - "element": { - "name": "icons" - }, - "children": [ - { - "element": { - "name": "full" - }, - "children": [ - { - "element": { - "name": "dlcl16" - }, - "children": [ - { - "element": { - "name": "changevariablevalue_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "changevariablevalue_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "clear_co.gif" - }, - "incompressible": true - }, - { - "element": { - "name": "collapseall.png" - }, - "incompressible": true - }, - { - "element": { - "name": "collapseall@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "copy_edit_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "copy_edit_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "copyviewtoclipboard_tsk.png" - }, - "incompressible": true - }, - { - "element": { - "name": "copyviewtoclipboard_tsk@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_view_auto.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_view_auto@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_view_compact.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_view_compact@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_view_tree.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_view_tree@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debuglast_co.gif.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debuglast_co.gif@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debuglast_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debuglast_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "delete_config.png" - }, - "incompressible": true - }, - { - "element": { - "name": "delete_config@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "det_pane_auto.png" - }, - "incompressible": true - }, - { - "element": { - "name": "det_pane_auto@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "det_pane_hide.png" - }, - "incompressible": true - }, - { - "element": { - "name": "det_pane_hide@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "det_pane_right.png" - }, - "incompressible": true - }, - { - "element": { - "name": "det_pane_right@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "det_pane_under.png" - }, - "incompressible": true - }, - { - "element": { - "name": "det_pane_under@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "disabled_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "disabled_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "disconnect_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "disconnect_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "display_selected_mb.png" - }, - "incompressible": true - }, - { - "element": { - "name": "display_selected_mb@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "dissolve_group.png" - }, - "incompressible": true - }, - { - "element": { - "name": "dissolve_group@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "drop_to_frame.png" - }, - "incompressible": true - }, - { - "element": { - "name": "drop_to_frame@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "edtsrclkup_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "edtsrclkup_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "enabled_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "enabled_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "expandall.png" - }, - "incompressible": true - }, - { - "element": { - "name": "expandall@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "export_brkpts.png" - }, - "incompressible": true - }, - { - "element": { - "name": "export_brkpts@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "export_config.png" - }, - "incompressible": true - }, - { - "element": { - "name": "export_config@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "filter_ps.png" - }, - "incompressible": true - }, - { - "element": { - "name": "filter_ps@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "hierarchicalLayout.png" - }, - "incompressible": true - }, - { - "element": { - "name": "hierarchicalLayout@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "import_brkpts.png" - }, - "incompressible": true - }, - { - "element": { - "name": "import_brkpts@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "link_proto.png" - }, - "incompressible": true - }, - { - "element": { - "name": "link_proto@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "lock_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "lock_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "memoryreset_tsk.png" - }, - "incompressible": true - }, - { - "element": { - "name": "memoryreset_tsk@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "metharg_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "metharg_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "monitorexpression_tsk.png" - }, - "incompressible": true - }, - { - "element": { - "name": "monitorexpression_tsk@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "new_con.png" - }, - "incompressible": true - }, - { - "element": { - "name": "new_con@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "new_proto.png" - }, - "incompressible": true - }, - { - "element": { - "name": "new_proto@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "next_thread_nav.png" - }, - "incompressible": true - }, - { - "element": { - "name": "next_thread_nav@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "pin.png" - }, - "incompressible": true - }, - { - "element": { - "name": "pin@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "prev_thread_nav.png" - }, - "incompressible": true - }, - { - "element": { - "name": "prev_thread_nav@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "printview_tsk.png" - }, - "incompressible": true - }, - { - "element": { - "name": "printview_tsk@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "prop_ps.png" - }, - "incompressible": true - }, - { - "element": { - "name": "prop_ps@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "rem_all_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "rem_all_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "rem_all_triggers.png" - }, - "incompressible": true - }, - { - "element": { - "name": "rem_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "rem_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "removememory_tsk.png" - }, - "incompressible": true - }, - { - "element": { - "name": "removememory_tsk@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "reset_proto.png" - }, - "incompressible": true - }, - { - "element": { - "name": "reset_proto@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "restart_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "restart_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "resume_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "resume_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "runlast_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "runlast_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "runtoline_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "runtoline_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "skip_brkp.png" - }, - "incompressible": true - }, - { - "element": { - "name": "skip_brkp@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stepbystep_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stepbystep_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stepinto_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stepinto_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stepover_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stepover_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stepreturn_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stepreturn_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "suspend_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "suspend_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "synced.png" - }, - "incompressible": true - }, - { - "element": { - "name": "synced@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "terminate_all_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "terminate_all_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "terminate_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "terminate_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "terminate_rem_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "terminate_rem_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "tnames_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "tnames_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "toggledetailpane_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "toggledetailpane_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "unlink_proto.png" - }, - "incompressible": true - }, - { - "element": { - "name": "unlink_proto@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "var_cntnt_prvdr.png" - }, - "incompressible": true - }, - { - "element": { - "name": "var_cntnt_prvdr@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "writeerr_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "writeerr_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "writeout_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "writeout_co@2x.png" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "dtool16" - }, - "children": [ - { - "element": { - "name": "debug_exc.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_exc@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "environment_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "environment_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "profile_exc.png" - }, - "incompressible": true - }, - { - "element": { - "name": "profile_exc@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "run_exc.png" - }, - "incompressible": true - }, - { - "element": { - "name": "run_exc@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "term_restart.png" - }, - "incompressible": true - }, - { - "element": { - "name": "term_restart@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "watch_exp.png" - }, - "incompressible": true - }, - { - "element": { - "name": "watch_exp@2x.png" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "dview16" - }, - "children": [ - { - "element": { - "name": "breakpoint_view.png" - }, - "incompressible": true - }, - { - "element": { - "name": "breakpoint_view@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_persp.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_persp@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_view.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_view@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "details_view.png" - }, - "incompressible": true - }, - { - "element": { - "name": "details_view@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "memory_view.png" - }, - "incompressible": true - }, - { - "element": { - "name": "memory_view@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "module_view.png" - }, - "incompressible": true - }, - { - "element": { - "name": "module_view@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "register_view.png" - }, - "incompressible": true - }, - { - "element": { - "name": "register_view@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "variable_view.png" - }, - "incompressible": true - }, - { - "element": { - "name": "variable_view@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "watchlist_view.png" - }, - "incompressible": true - }, - { - "element": { - "name": "watchlist_view@2x.png" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "elcl16" - }, - "children": [ - { - "element": { - "name": "changevariablevalue_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "changevariablevalue_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "collapseall.png" - }, - "incompressible": true - }, - { - "element": { - "name": "collapseall@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "copy_edit_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "copy_edit_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "copyviewtoclipboard_tsk.png" - }, - "incompressible": true - }, - { - "element": { - "name": "copyviewtoclipboard_tsk@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_view_auto.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_view_auto@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_view_compact.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_view_compact@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_view_tree.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_view_tree@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debuglast_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debuglast_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "delete_config.png" - }, - "incompressible": true - }, - { - "element": { - "name": "delete_config@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "det_pane_auto.png" - }, - "incompressible": true - }, - { - "element": { - "name": "det_pane_auto@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "det_pane_hide.png" - }, - "incompressible": true - }, - { - "element": { - "name": "det_pane_hide@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "det_pane_right.png" - }, - "incompressible": true - }, - { - "element": { - "name": "det_pane_right@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "det_pane_under.png" - }, - "incompressible": true - }, - { - "element": { - "name": "det_pane_under@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "disabled_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "disabled_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "disconnect_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "disconnect_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "display_selected_mb.png" - }, - "incompressible": true - }, - { - "element": { - "name": "display_selected_mb@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "dissolve_group.png" - }, - "incompressible": true - }, - { - "element": { - "name": "dissolve_group@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "drop_to_frame.png" - }, - "incompressible": true - }, - { - "element": { - "name": "drop_to_frame@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "edtsrclkup_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "edtsrclkup_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "enabled_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "enabled_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "expandall.png" - }, - "incompressible": true - }, - { - "element": { - "name": "expandall@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "export_brkpts.png" - }, - "incompressible": true - }, - { - "element": { - "name": "export_brkpts@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "export_config.png" - }, - "incompressible": true - }, - { - "element": { - "name": "export_config@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "filter_ps.png" - }, - "incompressible": true - }, - { - "element": { - "name": "filter_ps@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "hierarchicalLayout.png" - }, - "incompressible": true - }, - { - "element": { - "name": "hierarchicalLayout@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "import_brkpts.png" - }, - "incompressible": true - }, - { - "element": { - "name": "import_brkpts@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "link_proto.png" - }, - "incompressible": true - }, - { - "element": { - "name": "link_proto@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "lock_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "lock_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "memoryreset_tsk.png" - }, - "incompressible": true - }, - { - "element": { - "name": "memoryreset_tsk@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "metharg_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "metharg_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "monitorexpression_tsk.png" - }, - "incompressible": true - }, - { - "element": { - "name": "monitorexpression_tsk@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "new_con.png" - }, - "incompressible": true - }, - { - "element": { - "name": "new_con@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "new_proto.png" - }, - "incompressible": true - }, - { - "element": { - "name": "new_proto@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "next_thread_nav.png" - }, - "incompressible": true - }, - { - "element": { - "name": "next_thread_nav@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "pin.png" - }, - "incompressible": true - }, - { - "element": { - "name": "pin@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "prev_thread_nav.png" - }, - "incompressible": true - }, - { - "element": { - "name": "prev_thread_nav@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "printview_tsk.png" - }, - "incompressible": true - }, - { - "element": { - "name": "printview_tsk@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "prop_ps.png" - }, - "incompressible": true - }, - { - "element": { - "name": "prop_ps@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "rem_all_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "rem_all_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "rem_all_triggers.png" - }, - "incompressible": true - }, - { - "element": { - "name": "rem_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "rem_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "removememory_tsk.png" - }, - "incompressible": true - }, - { - "element": { - "name": "removememory_tsk@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "reset_proto.png" - }, - "incompressible": true - }, - { - "element": { - "name": "reset_proto@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "restart_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "restart_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "resume_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "resume_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "runlast_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "runlast_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "runtoline_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "runtoline_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "skip_brkp.png" - }, - "incompressible": true - }, - { - "element": { - "name": "skip_brkp@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stepbystep_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stepbystep_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stepinto_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stepinto_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stepover_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stepover_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stepreturn_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stepreturn_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "suspend_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "suspend_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "synced.png" - }, - "incompressible": true - }, - { - "element": { - "name": "synced@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "terminate_all_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "terminate_all_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "terminate_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "terminate_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "terminate_rem_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "terminate_rem_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "tnames_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "tnames_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "toggledetailpane_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "toggledetailpane_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "unlink_proto.png" - }, - "incompressible": true - }, - { - "element": { - "name": "unlink_proto@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "var_cntnt_prvdr.png" - }, - "incompressible": true - }, - { - "element": { - "name": "var_cntnt_prvdr@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "writeerr_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "writeerr_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "writeout_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "writeout_co@2x.png" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "etool16" - }, - "children": [ - { - "element": { - "name": "debug_exc.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_exc@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "environment_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "environment_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "profile_exc.png" - }, - "incompressible": true - }, - { - "element": { - "name": "profile_exc@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "run_exc.png" - }, - "incompressible": true - }, - { - "element": { - "name": "run_exc@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "term_restart.png" - }, - "incompressible": true - }, - { - "element": { - "name": "term_restart@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "watch_exp.png" - }, - "incompressible": true - }, - { - "element": { - "name": "watch_exp@2x.png" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "eview16" - }, - "children": [ - { - "element": { - "name": "breakpoint_view.gif" - }, - "incompressible": true - }, - { - "element": { - "name": "breakpoint_view.png" - }, - "incompressible": true - }, - { - "element": { - "name": "breakpoint_view@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_persp.gif" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_persp.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_persp@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_view.gif" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_view.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_view@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "details_view.gif" - }, - "incompressible": true - }, - { - "element": { - "name": "details_view.png" - }, - "incompressible": true - }, - { - "element": { - "name": "details_view@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "memory_view.gif" - }, - "incompressible": true - }, - { - "element": { - "name": "memory_view.png" - }, - "incompressible": true - }, - { - "element": { - "name": "memory_view@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "module_view.gif" - }, - "incompressible": true - }, - { - "element": { - "name": "module_view.png" - }, - "incompressible": true - }, - { - "element": { - "name": "module_view@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "register_view.gif" - }, - "incompressible": true - }, - { - "element": { - "name": "register_view.png" - }, - "incompressible": true - }, - { - "element": { - "name": "register_view@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "variable_view.gif" - }, - "incompressible": true - }, - { - "element": { - "name": "variable_view.png" - }, - "incompressible": true - }, - { - "element": { - "name": "variable_view@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "watchlist_view.gif" - }, - "incompressible": true - }, - { - "element": { - "name": "watchlist_view.png" - }, - "incompressible": true - }, - { - "element": { - "name": "watchlist_view@2x.png" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "obj16" - }, - "children": [ - { - "element": { - "name": "arraypartition_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "arraypartition_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "brkp_grp.png" - }, - "incompressible": true - }, - { - "element": { - "name": "brkp_grp@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "brkp_grp_disabled.png" - }, - "incompressible": true - }, - { - "element": { - "name": "brkp_grp_disabled@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "brkp_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "brkp_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "brkp_type.png" - }, - "incompressible": true - }, - { - "element": { - "name": "brkp_type@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "brkpd_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "brkpd_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "check.png" - }, - "incompressible": true - }, - { - "element": { - "name": "check@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "common_tab.png" - }, - "incompressible": true - }, - { - "element": { - "name": "common_tab@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debugt_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debugt_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debugts_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debugts_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debugtt_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debugtt_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "environment_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "environment_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "envvar_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "envvar_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "export_config_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "export_config_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "expression_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "expression_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "file_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "file_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "fldr_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "fldr_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "genericreggroup_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "genericreggroup_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "genericregister_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "genericregister_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "genericvariable_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "genericvariable_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "import_config_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "import_config_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "inst_ptr.png" - }, - "incompressible": true - }, - { - "element": { - "name": "inst_ptr@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "inst_ptr_top.png" - }, - "incompressible": true - }, - { - "element": { - "name": "inst_ptr_top@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "jar_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "jar_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "ldebug_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "ldebug_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "lgroup_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "lgroup_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "lrun_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "lrun_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "memory_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "memory_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "memorychanged_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "memorychanged_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "osprc_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "osprc_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "osprct_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "osprct_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "persp_tab.png" - }, - "incompressible": true - }, - { - "element": { - "name": "persp_tab@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "prj_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "prj_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "proto_tab.png" - }, - "incompressible": true - }, - { - "element": { - "name": "proto_tab@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "read_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "read_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "read_obj_disabled.png" - }, - "incompressible": true - }, - { - "element": { - "name": "read_obj_disabled@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "readwrite_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "readwrite_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "readwrite_obj_disabled.png" - }, - "incompressible": true - }, - { - "element": { - "name": "readwrite_obj_disabled@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "refresh_tab.png" - }, - "incompressible": true - }, - { - "element": { - "name": "refresh_tab@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "rundebug.png" - }, - "incompressible": true - }, - { - "element": { - "name": "rundebug@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stckframe_obj.gif" - }, - "incompressible": true - }, - { - "element": { - "name": "stckframe_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stckframe_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stckframe_running_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stckframe_running_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "terminatedlaunch_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "terminatedlaunch_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "thread_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "thread_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "threads_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "threads_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "threadt_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "threadt_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "uncheck.png" - }, - "incompressible": true - }, - { - "element": { - "name": "uncheck@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "workset.png" - }, - "incompressible": true - }, - { - "element": { - "name": "workset@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "write_obj.png" - }, - "incompressible": true - }, - { - "element": { - "name": "write_obj@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "write_obj_disabled.png" - }, - "incompressible": true - }, - { - "element": { - "name": "write_obj_disabled@2x.png" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "ovr16" - }, - "children": [ - { - "element": { - "name": "error.png" - }, - "incompressible": true - }, - { - "element": { - "name": "error@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "prototype.png" - }, - "incompressible": true - }, - { - "element": { - "name": "prototype@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "skip_breakpoint_ov.png" - }, - "incompressible": true - }, - { - "element": { - "name": "skip_breakpoint_ov@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stcksync_ov.png" - }, - "incompressible": true - }, - { - "element": { - "name": "stcksync_ov@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "transparent.png" - }, - "incompressible": true - }, - { - "element": { - "name": "transparent@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "var_cntnt_prvdr_ov.png" - }, - "incompressible": true - }, - { - "element": { - "name": "var_cntnt_prvdr_ov@2x.png" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "wizban" - }, - "children": [ - { - "element": { - "name": "adddir_wiz.png" - }, - "incompressible": true - }, - { - "element": { - "name": "addsrcloc_wiz.png" - }, - "incompressible": true - }, - { - "element": { - "name": "debug_wiz.png" - }, - "incompressible": true - }, - { - "element": { - "name": "editdir_wiz.png" - }, - "incompressible": true - }, - { - "element": { - "name": "edtsrclkup_wiz.png" - }, - "incompressible": true - }, - { - "element": { - "name": "export_brkpts_wizban.png" - }, - "incompressible": true - }, - { - "element": { - "name": "export_config_wizban.png" - }, - "incompressible": true - }, - { - "element": { - "name": "import_brkpts_wizban.png" - }, - "incompressible": true - }, - { - "element": { - "name": "import_config_wizban.png" - }, - "incompressible": true - }, - { - "element": { - "name": "profile_wiz.png" - }, - "incompressible": true - }, - { - "element": { - "name": "run_wiz.png" - }, - "incompressible": true - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "plugin.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "plugin.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "pom.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "schema" - }, - "children": [ - { - "element": { - "name": "breakpointOrganizers.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "consoleColorProviders.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "consoleLineTrackers.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "contextViewBindings.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "debugModelContextBindings.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "debugModelPresentations.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "detailPaneFactories.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "launchConfigurationTabGroups.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "launchConfigurationTabs.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "launchConfigurationTypeImages.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "launchGroups.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "launchShortcuts.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "memoryRenderings.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "sourceContainerPresentations.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "stringVariablePresentations.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "toggleBreakpointsTargetFactories.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "variableValueEditors.exsd" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "scripts" - }, - "children": [ - { - "element": { - "name": "exportplugin.xml" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "ui" - }, - "children": [ - { - "element": { - "name": "org" - }, - "children": [ - { - "element": { - "name": "eclipse" - }, - "children": [ - { - "element": { - "name": "debug" - }, - "children": [ - { - "element": { - "name": "internal" - }, - "children": [ - { - "element": { - "name": "ui" - }, - "children": [ - { - "element": { - "name": "AbstractDebugCheckboxSelectionDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AbstractDebugListSelectionDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AbstractDebugSelectionDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointImageProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BuildBeforeLaunchStatusHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ColorManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CompositeDebugImageDescriptor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugModelPropertyTester.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugPerspectiveFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugPluginImages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugUIAdapterFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugUIMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugUIMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugUIPlugin.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugUIPreferenceInitializer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DefaultLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DelegatingModelPresentation.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DynamicInstructionPointerAnnotation.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDebugHelpContextIds.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IInternalDebugUIConstants.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchHistoryChangedListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchLabelChangedListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ImageDescriptorRegistry.java" - }, - "incompressible": true - }, - { - "element": { - "name": "InstructionPointerAnnotation.java" - }, - "incompressible": true - }, - { - "element": { - "name": "InstructionPointerContext.java" - }, - "incompressible": true - }, - { - "element": { - "name": "InstructionPointerImageProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "InstructionPointerManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationTabExtension.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LazyModelPresentation.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MultipleInputDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "Pair.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ResourceExtender.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SWTFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TerminateToggleValue.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TextGetSetEditingSupport.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VariableValueEditorManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VariablesViewModelPresentation.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WorkingDirectoryStatusHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "actions" - }, - "children": [ - { - "element": { - "name": "AbstractDebugActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AbstractRemoveAllActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AbstractSelectionActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ActionMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ActionMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "AddToFavoritesAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CollapseAllAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConfigureColumnsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugAsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugContextualLaunchAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugHistoryMenuAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugLastAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugToolbarAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "EditLaunchConfigurationAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExecutionAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchShortcutAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchablePropertyTester.java" - }, - "incompressible": true - }, - { - "element": { - "name": "OpenDebugConfigurations.java" - }, - "incompressible": true - }, - { - "element": { - "name": "OpenProfileConfigurations.java" - }, - "incompressible": true - }, - { - "element": { - "name": "OpenRunConfigurations.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProfileAsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProfileContextualLaunchAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProfileHistoryMenuAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProfileLastAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProfileToolbarAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RelaunchActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RelaunchLastAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RemoveAllTerminatedAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RetargetAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RetargetRunToLineAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RunAsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RunContextualLaunchAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RunHistoryMenuAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RunLastAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RunToolbarAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SelectAllAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StatusInfo.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ToggleBreakpointsTargetManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ToggleFilterAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ViewManagementAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "breakpointGroups" - }, - "children": [ - { - "element": { - "name": "AbstractBreakpointsViewAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AdvancedGroupBreakpointsByAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointGroupMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointGroupMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointSelectionAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointWorkingSetAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ClearDefaultBreakpointGroupAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CopyBreakpointsActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "EditBreakpointGroupAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "GroupBreakpointsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "GroupBreakpointsByAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "GroupBreakpointsByDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PasteBreakpointsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RemoveFromWorkingSetAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SelectBreakpointWorkingsetDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SetDefaultBreakpointGroupAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ToggleDefaultGroupAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WorkingSetsAction.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "breakpointSortBy" - }, - "children": [ - { - "element": { - "name": "Messages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "Messages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "SortBreakpointsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SortBreakpointsByAction.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "breakpoints" - }, - "children": [ - { - "element": { - "name": "AccessWatchpointToggleAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointsCollapseAllAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointsExpandAllAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DeleteWorkingsetsMessageDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DisableBreakpointsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "EnableBreakpointsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LinkBreakpointsWithDebugViewAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "Messages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "Messages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "ModificationWatchpointToggleAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ModifyWatchpointAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "OpenBreakpointMarkerAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RemoveAllBreakpointsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RemoveAllTriggerPointsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RemoveBreakpointAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RetargetBreakpointAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RetargetMethodBreakpointAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RetargetToggleBreakpointAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RetargetToggleLineBreakpointAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RetargetWatchpointAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RulerEnableDisableBreakpointAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SelectAllBreakpointsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ShowSupportedBreakpointsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ShowTargetBreakpointsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SkipAllBreakpointsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ToggleBreakpointObjectActionDelegate.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "expressions" - }, - "children": [ - { - "element": { - "name": "AddWatchExpressionAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConvertToWatchExpressionAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CopyExpressionsToClipboardActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DisableWatchExpressionAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "EditWatchExpressinInPlaceAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "EditWatchExpressionAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "EnableWatchExpressionAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PasteWatchExpressionsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ReevaluateWatchExpressionAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RemoveAllExpressionsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RemoveExpressionAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SelectAllExpressionsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WatchExpressionAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WatchExpressionDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WatchExpressionFactoryTester.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WatchHandler.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "variables" - }, - "children": [ - { - "element": { - "name": "ChangeVariableValueAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ChangeVariableValueInputDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SelectAllVariablesAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ShowTypesAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ToggleDetailPaneAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "details" - }, - "children": [ - { - "element": { - "name": "DetailPaneAssignValueAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DetailPaneMaxLengthAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DetailPaneMaxLengthDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DetailPaneWordWrapAction.java" - }, - "incompressible": true - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "breakpoints" - }, - "children": [ - { - "element": { - "name": "provisional" - }, - "children": [ - { - "element": { - "name": "IBreakpointContainer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IBreakpointOrganizer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IBreakpointUIConstants.java" - }, - "incompressible": true - }, - { - "element": { - "name": "OtherBreakpointCategory.java" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "commands" - }, - "children": [ - { - "element": { - "name": "actions" - }, - "children": [ - { - "element": { - "name": "AbstractRequestMonitor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ActionsUpdater.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugActionHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugCommandActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugCommandService.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DisconnectCommandAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DisconnectCommandActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DisconnectCommandHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DropToFrameCommandAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DropToFrameCommandActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DropToFrameCommandHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExecuteActionRequest.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ICommandParticipant.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IEnabledTarget.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RestartCommandAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RestartCommandActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RestartCommandHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ResumeCommandAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ResumeCommandActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ResumeCommandHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StepIntoCommandAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StepIntoCommandActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StepIntoCommandHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StepOverCommandAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StepOverCommandActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StepOverCommandHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StepReturnCommandAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StepReturnCommandActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StepReturnCommandHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SuspendCommandAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SuspendCommandActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SuspendCommandHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TerminateAllAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TerminateAllActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TerminateAndRelaunchAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TerminateAndRelaunchHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TerminateAndRemoveAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TerminateCommandAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TerminateCommandActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TerminateCommandHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ToggleStepFiltersAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ToggleStepFiltersCommandActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ToggleStepFiltersCommandHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "UpdateActionsRequest.java" - }, - "incompressible": true - }, - { - "element": { - "name": "UpdateHandlerRequest.java" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "contextlaunching" - }, - "children": [ - { - "element": { - "name": "ContextMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ContextMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "ContextRunner.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchingResourceManager.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "contexts" - }, - "children": [ - { - "element": { - "name": "DebugContextManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugContextSourceProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugModelContextBindingManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugWindowContextService.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchSuspendTrigger.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SuspendTriggerAdapterFactory.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "elements" - }, - "children": [ - { - "element": { - "name": "adapters" - }, - "children": [ - { - "element": { - "name": "AsynchronousDebugLabelAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DefaultBreakpointsViewInput.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DefaultVariableCellModifier.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DefaultViewerInputProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryBlockContentAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryBlockLabelAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryRetrievalContentAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemorySegmentLabelAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "Messages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "Messages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "RegisterGroupProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StackFrameSourceDisplayAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StackFrameViewerInputProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VariableColumnFactoryAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VariableColumnPresentation.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WatchExpressionCellModifier.java" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "groups" - }, - "children": [ - { - "element": { - "name": "CommonTabLite.java" - }, - "incompressible": true - }, - { - "element": { - "name": "GroupCycleHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "GroupElementLaunchedHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "GroupLaunchConfigurationSelectionDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "GroupLaunchConfigurationTabGroup.java" - }, - "incompressible": true - }, - { - "element": { - "name": "GroupLaunchHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "UnsupportedModeHandler.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "hover" - }, - "children": [ - { - "element": { - "name": "DebugTextHover.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExpressionInformationControlCreator.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "importexport" - }, - "children": [ - { - "element": { - "name": "breakpoints" - }, - "children": [ - { - "element": { - "name": "BreakpointImportExport.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointsPathDecorator.java" - }, - "incompressible": true - }, - { - "element": { - "name": "EmbeddedBreakpointsViewer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExportBreakpoints.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IImportExportConstants.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ImportBreakpoints.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ImportExportMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WizardExportBreakpoints.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WizardExportBreakpointsPage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WizardImportBreakpoints.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WizardImportBreakpointsPage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WizardImportBreakpointsSelectionPage.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "launchconfigurations" - }, - "children": [ - { - "element": { - "name": "ExportLaunchConfigurationsWizard.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExportLaunchConfigurationsWizardPage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ImportLaunchConfigurationsWizard.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ImportLaunchConfigurationsWizardPage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WizardMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WizardMessages.properties" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "launchConfigurations" - }, - "children": [ - { - "element": { - "name": "AbstractLaunchConfigurationAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ClosedProjectFilter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CollapseAllLaunchConfigurationAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CompileErrorProjectPromptStatusHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CompileErrorPromptStatusHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CreateLaunchConfigurationAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CreateLaunchConfigurationPrototypeAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugModePromptStatusHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DeleteLaunchConfigurationAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DeletedProjectFilter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DuplicateLaunchConfigurationAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DuplicateLaunchDelegatesStatusHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "EnvironmentVariable.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExportLaunchConfigurationAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "FavoritesDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "FilterDropDownMenuCreator.java" - }, - "incompressible": true - }, - { - "element": { - "name": "FilterLaunchConfigurationAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchCategoryFilter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationComparator.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationEditDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationFilteredTree.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationPresentationManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationPropertiesDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationSelectionDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationTabGroupExtension.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationTabGroupViewer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationTabGroupWrapper.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationTabImageDescriptor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationTreeContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationTypeContribution.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationTypeFilter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationView.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationViewer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationsDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationsMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationsMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchDelegateContribution.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchDelegateNotAvailableHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchGroupExtension.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchGroupFilter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchHistory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchShortcutExtension.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchShortcutSelectionDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchTabContribution.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LinkPrototypeAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "OrganizeFavoritesAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PerspectiveManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ResetWithPrototypeValuesAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SaveScopeResourcesHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SelectFavoritesDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SelectLaunchModesDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SelectLaunchersDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ShowCommandLineDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "UnlinkPrototypeAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WorkingSetComparator.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WorkingSetsFilter.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "memory" - }, - "children": [ - { - "element": { - "name": "IMemoryBlockConnection.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMemoryRenderingUpdater.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IPersistableDebugElement.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryRenderingManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryRenderingType.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RenderingBindings.java" - }, - "incompressible": true - }, - { - "element": { - "name": "provisional" - }, - "children": [ - { - "element": { - "name": "AbstractAsyncTableRendering.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AbstractAsyncTextRendering.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryViewPresentationContext.java" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "model" - }, - "children": [ - { - "element": { - "name": "elements" - }, - "children": [ - { - "element": { - "name": "BreakpointContainerLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointContainerMementoProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointManagerContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointManagerInputMementoProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointMementoProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugElementLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugElementMementoProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugTargetContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ElementContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ElementLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ElementMementoProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExpressionContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExpressionLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExpressionManagerContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExpressionManagerMementoProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExpressionMementoProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchManagerContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryBlockContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryBlockLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryRetrievalContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryViewElementMementoProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProcessContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RegisterGroupContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RegisterGroupLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RegisterGroupMementoProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StackFrameContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StackFrameMementoProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ThreadContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VariableContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VariableEditor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VariableLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VariableMementoProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ViewerInputProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WatchExpressionEditor.java" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "preferences" - }, - "children": [ - { - "element": { - "name": "BooleanFieldEditor2.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsolePreferencePage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugPreferencePage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugPreferencesMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugPreferencesMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "IDebugPreferenceConstants.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchConfigurationsPreferencePage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchPerspectivePreferencePage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchersPreferencePage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchingPreferencePage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProcessPropertyPage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RunDebugPropertiesPage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StringVariablePreferencePage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ViewManagementPreferencePage.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "quickaccess" - }, - "children": [ - { - "element": { - "name": "AbstractLaunchQuickAccessComputer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugQuickAccessComputer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchQuickAccessElement.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProfileQuickAccessComputer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RunQuickAccessComputer.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "sourcelookup" - }, - "children": [ - { - "element": { - "name": "AddContainerAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AddSourceContainerDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BasicContainerContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DownAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "EditContainerAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "EditSourceLookupPathAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LookupSourceAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "Prompter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RemoveAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ResolveDuplicatesHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RestoreDefaultAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceContainerAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceContainerAdapterFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceContainerLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceContainerViewer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceContainerWorkbenchAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceElementAdapterFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceElementLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceElementWorkbenchAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceLookupFacility.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceLookupManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceLookupPanel.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceLookupResult.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceLookupService.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceLookupUIMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceLookupUIMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceLookupUIUtils.java" - }, - "incompressible": true - }, - { - "element": { - "name": "UpAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WorkingSetSourceContainerType.java" - }, - "incompressible": true - }, - { - "element": { - "name": "browsers" - }, - "children": [ - { - "element": { - "name": "ArchiveFilter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ArchiveSourceContainerBrowser.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DirectorySourceContainerBrowser.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DirectorySourceContainerDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalArchiveSourceContainerBrowser.java" - }, - "incompressible": true - }, - { - "element": { - "name": "FolderSourceContainerBrowser.java" - }, - "incompressible": true - }, - { - "element": { - "name": "FolderSourceContainerDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProjectSourceContainerBrowser.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProjectSourceContainerDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WorkingSetSourceContainerBrowser.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WorkspaceSourceContainerBrowser.java" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "stringsubstitution" - }, - "children": [ - { - "element": { - "name": "FilePrompt.java" - }, - "incompressible": true - }, - { - "element": { - "name": "FolderPrompt.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IArgumentSelector.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PasswordPrompt.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PromptingResolver.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ResourceSelector.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SelectedResourceManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SelectedResourceResolver.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SelectedTextResolver.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StringPrompt.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StringSubstitutionMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StringSubstitutionMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "StringVariableLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StringVariablePresentationManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SystemPropertyArgumentSelector.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "viewers" - }, - "children": [ - { - "element": { - "name": "AbstractUpdatePolicy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AsynchronousModel.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AsynchronousRequestMonitor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AsynchronousSchedulingRuleFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AsynchronousTableModel.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AsynchronousTableViewer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AsynchronousViewer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ChildrenRequestMonitor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "FindElementDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILabelResult.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LabelRequestMonitor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LabelResult.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ModelNode.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PartPresentationContext.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TableAddRequestMonitor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TableEditorImpl.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TableInsertRequestMonitor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TableRemoveRequestMonitor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TableReplaceRequestMonitor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TableUpdatePolicy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "breadcrumb" - }, - "children": [ - { - "element": { - "name": "AbstractBreadcrumb.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreadcrumbItem.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreadcrumbItemDetails.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreadcrumbItemDropDown.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreadcrumbMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreadcrumbMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "BreadcrumbViewer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IBreadcrumbDropDownSite.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TreeViewerDropDown.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "model" - }, - "children": [ - { - "element": { - "name": "ChildrenCountUpdate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ChildrenUpdate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ElementCompareRequest.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ElementMementoRequest.java" - }, - "incompressible": true - }, - { - "element": { - "name": "FilterTransform.java" - }, - "incompressible": true - }, - { - "element": { - "name": "HasChildrenUpdate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IInternalTreeModelViewer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILabelUpdateListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ITreeModelContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ITreeModelLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ITreeModelViewer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "InternalTreeModelViewer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "InternalVirtualTreeModelViewer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LabelUpdate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MementoUpdate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SubTreeModelViewer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TimeTriggeredProgressMonitorDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TreeModelContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TreeModelLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ViewerAdapterService.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ViewerInputUpdate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ViewerStateTracker.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ViewerUpdateMonitor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VirtualCopyToClipboardActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VirtualFindAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "provisional" - }, - "children": [ - { - "element": { - "name": "ICheckUpdate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ICheckboxModelProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IChildrenCountUpdate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IChildrenUpdate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IColumnPresentation.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IColumnPresentation2.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IColumnPresentationFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IElementCompareRequest.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IElementContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IElementEditor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IElementLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IElementMementoProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IElementMementoRequest.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IHasChildrenUpdate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILabelUpdate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IModelChangedListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IModelDelta.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IModelDeltaVisitor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IModelProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IModelProxy2.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IModelProxyFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IModelProxyFactory2.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IModelSelectionPolicy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IModelSelectionPolicyFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IPresentationContext.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IStateUpdateListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IStatusMonitor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ITreeModelViewer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IViewActionProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IViewerInputProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IViewerInputRequestor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IViewerInputUpdate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IViewerUpdate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IViewerUpdateListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IVirtualItemListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IVirtualItemValidator.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ModelDelta.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PresentationContext.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TreeModelViewer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TreeModelViewerFilter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ViewerInputService.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VirtualItem.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VirtualTree.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VirtualTreeModelViewer.java" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "provisional" - }, - "children": [ - { - "element": { - "name": "AbstractColumnPresentation.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AbstractModelProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AsynchronousContentAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AsynchronousLabelAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IAsynchronousContentAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IAsynchronousLabelAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IChildrenRequestMonitor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IContainerRequestMonitor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILabelRequestMonitor.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "update" - }, - "children": [ - { - "element": { - "name": "BreakpointContainerProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointManagerProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugEventHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugTargetEventHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugTargetProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DefaultExpressionModelProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DefaultModelProxyFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DefaultModelSelectionPolicyFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DefaultSelectionPolicy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DefaultVariableViewModelProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DefaultWatchExpressionModelProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "EventHandlerModelProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExpressionEventHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExpressionManagerModelProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchManagerProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryBlockProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryRetrievalProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProcessProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StackFrameEventHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ThreadEventHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VariablesViewEventHandler.java" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "views" - }, - "children": [ - { - "element": { - "name": "DebugModelPresentationContext.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugUIViewsMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugUIViewsMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "IDebugExceptionHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ViewContextManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ViewContextService.java" - }, - "incompressible": true - }, - { - "element": { - "name": "breakpoints" - }, - "children": [ - { - "element": { - "name": "BreakpointContainer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointContainerWorkbenchAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointOrganizerExtension.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointOrganizerManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointPersistableElementAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointSetOrganizer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointTypeOrganizer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointWorkingSetCache.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointWorkingSetElementAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointWorkingSetPage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointsComparator.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointsContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointsDragAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointsDropAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointsLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointsView.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointsViewer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ElementComparator.java" - }, - "incompressible": true - }, - { - "element": { - "name": "FileBreakpointOrganizer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProjectBreakpointOrganizer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WorkingSetBreakpointOrganizer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WorkingSetCategory.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "console" - }, - "children": [ - { - "element": { - "name": "ConsoleLineNotifier.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleRemoveAllTerminatedAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleRemoveLaunchAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleShowPreferencesAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleTerminateAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProcessConsole.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProcessConsoleManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProcessConsolePageParticipant.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProcessTypePropertyTester.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ShowStandardErrorAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ShowStandardOutAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ShowWhenContentChangesAction.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "expression" - }, - "children": [ - { - "element": { - "name": "ExpressionDropAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExpressionView.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "launch" - }, - "children": [ - { - "element": { - "name": "BreadcrumbDropDownAutoExpandAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreadcrumbWorkbenchPart.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugElementAdapterFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugElementHelper.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugToolBarAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugViewModeAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "Decoration.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DecorationManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ImageImageDescriptor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchView.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchViewBreadcrumb.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchViewCopyToClipboardActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchViewMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchViewMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceNotFoundEditor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceNotFoundEditorInput.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StandardDecoration.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TerminateAndRemoveHandler.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "memory" - }, - "children": [ - { - "element": { - "name": "AbstractMemoryViewPane.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AddMemoryBlockAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AddMemoryRenderingAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AddMemoryRenderingContextAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AddMemoryRenderingDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CodePagesPreferencePage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMemoryView.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMemoryViewPane.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMemoryViewTab.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LinkRenderingPanesAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryBlocksTreeViewPane.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryView.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryViewIdRegistry.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryViewPrefAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryViewSynchronizationService.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryViewTab.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryViewTreeModelContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryViewTreeViewer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryViewUtil.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MonitorMemoryBlockDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "NewMemoryViewAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PinMemoryBlockAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PropertyChangeNotifier.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RemoveMemoryRenderingAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RemoveRenderingContextAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RenderingViewPane.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ResetMemoryBlockAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ResetMemoryBlockPreferencePage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RetargetAddMemoryBlockAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SetPaddedStringPreferencePage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SwitchMemoryBlockAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SynchronizeInfo.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ToggleMemoryMonitorsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ToggleSplitPaneAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ToggleViewPaneAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ViewPaneOrientationAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ViewPaneRenderingMgr.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ViewPaneSelectionProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ViewTabEnablementManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "renderings" - }, - "children": [ - { - "element": { - "name": "ASCIIRendering.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ASCIIRenderingTypeDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AbstractBaseTableRendering.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AbstractIntegerRendering.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AbstractTableRenderingLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AbstractVirtualContentTableModel.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AsyncCopyTableRenderingAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AsyncPrintTableRenderingAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AsyncTableRenderingCellModifier.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AsyncTableRenderingUpdatePolicy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AsyncTableRenderingViewer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AsyncVirtualContentTableViewer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BasicDebugViewContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BigEndianAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CopyTableRenderingToClipboardAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CreateRendering.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DefaultEndianessAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ErrorRendering.java" - }, - "incompressible": true - }, - { - "element": { - "name": "FormatTableRenderingAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "FormatTableRenderingDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "GoToAddressAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "GoToAddressComposite.java" - }, - "incompressible": true - }, - { - "element": { - "name": "GoToAddressDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "HexIntegerRendering.java" - }, - "incompressible": true - }, - { - "element": { - "name": "HexIntegerRenderingDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "HexRendering.java" - }, - "incompressible": true - }, - { - "element": { - "name": "HexRenderingTypeDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IContentChangeComputer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IPresentationErrorListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IVirtualContentListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LittleEndianAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemorySegment.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PendingPropertyChanges.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PrintTableRenderingAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ReformatAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RenderingsUtil.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ResetToBaseAddressAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SignedIntegerRendering.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SignedIntegerRenderingTypeDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TableRenderingCellModifier.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TableRenderingContentDescriptor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TableRenderingContentInput.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TableRenderingContentProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TableRenderingLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TableRenderingLabelProviderEx.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TableRenderingLine.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TableRenderingModel.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TableRenderingPrefAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TableRenderingPreferencePage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TableRenderingPropertiesPage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "UnsignedIntegerRendering.java" - }, - "incompressible": true - }, - { - "element": { - "name": "UnsignedIntegerRenderingTypeDelegate.java" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "modules" - }, - "children": [ - { - "element": { - "name": "IHelpContextIdProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ModulesView.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ModulesViewMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ModulesViewMessages.properties" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "registers" - }, - "children": [ - { - "element": { - "name": "RegistersView.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RegistersViewMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RegistersViewMessages.properties" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "variables" - }, - "children": [ - { - "element": { - "name": "AvailableLogicalStructuresAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "EditVariableLogicalStructureAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IndexedValuePartition.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IndexedVariablePartition.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LogicalStructureCache.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SelectLogicalStructureAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SelectionDragAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ToggleLogicalStructureAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ToggleShowColumnsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VariableViewToggleAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VariablesView.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VariablesViewMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VariablesViewMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "VariablesViewResourceBundleMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "details" - }, - "children": [ - { - "element": { - "name": "AbstractDetailPane.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AvailableDetailPanesAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DefaultDetailPane.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DefaultDetailPaneFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DetailMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DetailMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "DetailPaneManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DetailPaneProxy.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDetailPaneContainer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDetailPaneContainer2.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MessageDetailPane.java" - }, - "incompressible": true - } - ] - } - ] - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "ui" - }, - "children": [ - { - "element": { - "name": "AbstractBreakpointOrganizerDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AbstractDebugView.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AbstractLaunchConfigurationTab.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AbstractLaunchConfigurationTabGroup.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointTypeCategory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CommonTab.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugElementWorkbenchAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugPopup.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugUITools.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DeferredDebugElementWorkbenchAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "EnvironmentTab.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IBreakpointOrganizerDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IBreakpointOrganizerDelegateExtension.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IBreakpointTypeCategory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDebugEditorPresentation.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDebugModelPresentation.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDebugModelPresentationExtension.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDebugUIConstants.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDebugView.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDetailPane.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDetailPane2.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDetailPane3.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDetailPaneFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IInstructionPointerPresentation.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchConfigurationDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchConfigurationTab.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchConfigurationTab2.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchConfigurationTabGroup.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchGroup.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchShortcut.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchShortcut2.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ISourcePresentation.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IValueDetailListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "InspectPopupDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PrototypeDecorator.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PrototypeTab.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RefreshTab.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StringVariableSelectionDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WorkingDirectoryBlock.java" - }, - "incompressible": true - }, - { - "element": { - "name": "actions" - }, - "children": [ - { - "element": { - "name": "AbstractLaunchHistoryAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AbstractLaunchToolbarAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AddMemoryRenderingActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BreakpointTypesContribution.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ContextualLaunchAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugCommandAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugCommandHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExportBreakpointsOperation.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IAddMemoryBlocksTarget.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IAddMemoryRenderingsTarget.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ILaunchable.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IRunToLineTarget.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IToggleBreakpointsTarget.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IToggleBreakpointsTargetExtension.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IToggleBreakpointsTargetExtension2.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IToggleBreakpointsTargetFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IToggleBreakpointsTargetManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IToggleBreakpointsTargetManagerListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IVariableValueEditor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IWatchExpressionFactoryAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IWatchExpressionFactoryAdapter2.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IWatchExpressionFactoryAdapterExtension.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ImportBreakpointsOperation.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchAsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "LaunchShortcutsAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "OpenLaunchDialogAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RelaunchLastAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RulerBreakpointAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RulerBreakpointTypesActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RulerEnableDisableBreakpointActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RulerRunToLineActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RulerToggleBreakpointActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RunAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RunToLineAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RunToLineActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "RunToLineHandler.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ToggleBreakpointAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ToggleMethodBreakpointActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ToggleWatchpointActionDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "package.html" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "console" - }, - "children": [ - { - "element": { - "name": "ConsoleColorProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "FileLink.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IConsole.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IConsoleColorProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IConsoleHyperlink.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IConsoleLineTracker.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IConsoleLineTrackerExtension.java" - }, - "incompressible": true - }, - { - "element": { - "name": "package.html" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "contexts" - }, - "children": [ - { - "element": { - "name": "AbstractDebugContextProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "DebugContextEvent.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDebugContextListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDebugContextManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDebugContextProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDebugContextProvider2.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IDebugContextService.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ISuspendTrigger.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ISuspendTriggerListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "package.html" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "memory" - }, - "children": [ - { - "element": { - "name": "AbstractMemoryRendering.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AbstractMemoryRenderingBindingsProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AbstractTableRendering.java" - }, - "incompressible": true - }, - { - "element": { - "name": "AbstractTextRendering.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMemoryBlockTablePresentation.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMemoryRendering.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMemoryRenderingBindingsListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMemoryRenderingBindingsProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMemoryRenderingContainer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMemoryRenderingManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMemoryRenderingSite.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMemoryRenderingSite2.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMemoryRenderingSynchronizationService.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMemoryRenderingType.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IMemoryRenderingTypeDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IRepositionableMemoryRendering.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IResettableMemoryRendering.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MemoryRenderingElement.java" - }, - "incompressible": true - }, - { - "element": { - "name": "package.html" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "package.html" - }, - "incompressible": true - }, - { - "element": { - "name": "sourcelookup" - }, - "children": [ - { - "element": { - "name": "AbstractSourceContainerBrowser.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CommonSourceNotFoundEditor.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CommonSourceNotFoundEditorInput.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ISourceContainerBrowser.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ISourceDisplay.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ISourceLookupResult.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceLookupDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SourceLookupTab.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WorkingSetSourceContainer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "package.html" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "stringsubstitution" - }, - "children": [ - { - "element": { - "name": "IArgumentSelector.java" - }, - "incompressible": true - }, - { - "element": { - "name": "package.html" - }, - "incompressible": true - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "org.eclipse.ui.console" - }, - "children": [ - { - "element": { - "name": ".classpath" - }, - "incompressible": true - }, - { - "element": { - "name": ".project" - }, - "incompressible": true - }, - { - "element": { - "name": ".settings" - }, - "children": [ - { - "element": { - "name": "org.eclipse.core.resources.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.core.runtime.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.core.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.ui.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.pde.api.tools.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.pde.prefs" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "META-INF" - }, - "children": [ - { - "element": { - "name": "MANIFEST.MF" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "about.html" - }, - "incompressible": true - }, - { - "element": { - "name": "build.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "icons" - }, - "children": [ - { - "element": { - "name": "full" - }, - "children": [ - { - "element": { - "name": "clcl16" - }, - "children": [ - { - "element": { - "name": "clear_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "clear_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "lock_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "lock_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "pin.png" - }, - "incompressible": true - }, - { - "element": { - "name": "pin@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "wordwrap.png" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "cview16" - }, - "children": [ - { - "element": { - "name": "console_view.gif" - }, - "incompressible": true - }, - { - "element": { - "name": "console_view.png" - }, - "incompressible": true - }, - { - "element": { - "name": "console_view@2x.png" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "dlcl16" - }, - "children": [ - { - "element": { - "name": "clear_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "clear_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "lock_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "lock_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "new_con.png" - }, - "incompressible": true - }, - { - "element": { - "name": "new_con@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "pin.png" - }, - "incompressible": true - }, - { - "element": { - "name": "pin@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "rem_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "rem_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "wordwrap.png" - }, - "incompressible": true - }, - { - "element": { - "name": "wordwrap@2x.png" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "dview16" - }, - "children": [ - { - "element": { - "name": "console_view.png" - }, - "incompressible": true - }, - { - "element": { - "name": "console_view@2x.png" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "elcl16" - }, - "children": [ - { - "element": { - "name": "clear_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "clear_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "lock_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "lock_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "new_con.png" - }, - "incompressible": true - }, - { - "element": { - "name": "new_con@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "pin.png" - }, - "incompressible": true - }, - { - "element": { - "name": "pin@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "rem_co.png" - }, - "incompressible": true - }, - { - "element": { - "name": "rem_co@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "wordwrap.png" - }, - "incompressible": true - }, - { - "element": { - "name": "wordwrap@2x.png" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "eview16" - }, - "children": [ - { - "element": { - "name": "console_view.gif" - }, - "incompressible": true - }, - { - "element": { - "name": "console_view.png" - }, - "incompressible": true - }, - { - "element": { - "name": "console_view@2x.png" - }, - "incompressible": true - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "plugin.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "plugin.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "pom.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "schema" - }, - "children": [ - { - "element": { - "name": "consoleFactories.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "consolePageParticipants.exsd" - }, - "incompressible": true - }, - { - "element": { - "name": "consolePatternMatchListeners.exsd" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "scripts" - }, - "children": [ - { - "element": { - "name": "exportplugin.xml" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "src" - }, - "children": [ - { - "element": { - "name": "org" - }, - "children": [ - { - "element": { - "name": "eclipse" - }, - "children": [ - { - "element": { - "name": "ui" - }, - "children": [ - { - "element": { - "name": "console" - }, - "children": [ - { - "element": { - "name": "AbstractConsole.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsolePlugin.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IConsole.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IConsoleConstants.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IConsoleDocumentPartitioner.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IConsoleFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IConsoleListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IConsoleManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IConsolePageParticipant.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IConsoleView.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IHyperlink.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IHyperlink2.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IOConsole.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IOConsoleInputStream.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IOConsoleOutputStream.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IPatternMatchListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IPatternMatchListenerDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IScrollLockStateProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MessageConsole.java" - }, - "incompressible": true - }, - { - "element": { - "name": "MessageConsoleStream.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PatternMatchEvent.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TextConsole.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TextConsolePage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TextConsoleViewer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "actions" - }, - "children": [ - { - "element": { - "name": "ClearOutputAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "CloseConsoleAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TextViewerAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TextViewerGotoLineAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "package.html" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "package.html" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "internal" - }, - "children": [ - { - "element": { - "name": "console" - }, - "children": [ - { - "element": { - "name": "ConsoleDocument.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleDocumentAdapter.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleDropDownAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleFactoryExtension.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleHyperlinkPosition.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleManager.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsolePageParticipantExtension.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsolePatternMatcher.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsolePluginImages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleResourceBundleMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleResourceBundleMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleTypePropertyTester.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleUIPreferenceInitializer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleView.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleViewConsoleFactory.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ConsoleWorkbenchPart.java" - }, - "incompressible": true - }, - { - "element": { - "name": "FollowHyperlinkAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "HyperlinkUpdater.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IConsoleHelpContextIds.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IInternalConsoleConstants.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IOConsolePage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IOConsolePartition.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IOConsolePartitioner.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IOConsoleViewer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "OpenConsoleAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PatternMatchListener.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PatternMatchListenerExtension.java" - }, - "incompressible": true - }, - { - "element": { - "name": "PinConsoleAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ScrollLockAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ShowConsoleAction.java" - }, - "incompressible": true - }, - { - "element": { - "name": "StreamDecoder.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WordWrapAction.java" - }, - "incompressible": true - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "org.eclipse.ui.externaltools" - }, - "children": [ - { - "element": { - "name": ".classpath" - }, - "incompressible": true - }, - { - "element": { - "name": ".gitignore" - }, - "incompressible": true - }, - { - "element": { - "name": ".project" - }, - "incompressible": true - }, - { - "element": { - "name": ".settings" - }, - "children": [ - { - "element": { - "name": ".api_filters" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.core.resources.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.core.runtime.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.core.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.jdt.ui.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.pde.api.tools.prefs" - }, - "incompressible": true - }, - { - "element": { - "name": "org.eclipse.pde.prefs" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "External Tools Base" - }, - "children": [ - { - "element": { - "name": "org" - }, - "children": [ - { - "element": { - "name": "eclipse" - }, - "children": [ - { - "element": { - "name": "ui" - }, - "children": [ - { - "element": { - "name": "externaltools" - }, - "children": [ - { - "element": { - "name": "internal" - }, - "children": [ - { - "element": { - "name": "launchConfigurations" - }, - "children": [ - { - "element": { - "name": "ExternalToolsBuildTab.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolsBuilderTab.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolsLaunchConfigurationMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolsLaunchConfigurationMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolsMainTab.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolsUtil.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IgnoreWhiteSpaceComparator.java" - }, - "incompressible": true - }, - { - "element": { - "name": "WorkingSetComparator.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "menu" - }, - "children": [ - { - "element": { - "name": "ExternalToolMenuDelegate.java" - }, - "incompressible": true - }, - { - "element": { - "name": "OpenExternalToolsConfigurations.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "model" - }, - "children": [ - { - "element": { - "name": "BuilderUtils.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolsImages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolsModelMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolsModelMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolsPlugin.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolsPreferenceInitializer.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IExternalToolConstants.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IExternalToolsHelpContextIds.java" - }, - "incompressible": true - }, - { - "element": { - "name": "IPreferenceConstants.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ImageDescriptorRegistry.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "ui" - }, - "children": [ - { - "element": { - "name": "BuilderLabelProvider.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BuilderPropertyPage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "EditCommandDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolsPreferencePage.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolsUIMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolsUIMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "FileSelectionDialog.java" - }, - "incompressible": true - }, - { - "element": { - "name": "TreeAndListGroup.java" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "variables" - }, - "children": [ - { - "element": { - "name": "BuildFilesResolver.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BuildProjectResolver.java" - }, - "incompressible": true - }, - { - "element": { - "name": "BuildTypeResolver.java" - }, - "incompressible": true - }, - { - "element": { - "name": "SystemPathResolver.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VariableMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "VariableMessages.properties" - }, - "incompressible": true - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "META-INF" - }, - "children": [ - { - "element": { - "name": "MANIFEST.MF" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "Program Tools Support" - }, - "children": [ - { - "element": { - "name": "org" - }, - "children": [ - { - "element": { - "name": "eclipse" - }, - "children": [ - { - "element": { - "name": "ui" - }, - "children": [ - { - "element": { - "name": "externaltools" - }, - "children": [ - { - "element": { - "name": "internal" - }, - "children": [ - { - "element": { - "name": "program" - }, - "children": [ - { - "element": { - "name": "launchConfigurations" - }, - "children": [ - { - "element": { - "name": "ExternalToolsProgramMessages.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ExternalToolsProgramMessages.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "ProgramBuilderTabGroup.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProgramMainTab.java" - }, - "incompressible": true - }, - { - "element": { - "name": "ProgramTabGroup.java" - }, - "incompressible": true - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "about.html" - }, - "incompressible": true - }, - { - "element": { - "name": "build.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "icons" - }, - "children": [ - { - "element": { - "name": "full" - }, - "children": [ - { - "element": { - "name": "dtool16" - }, - "children": [ - { - "element": { - "name": "external_tools.png" - }, - "incompressible": true - }, - { - "element": { - "name": "external_tools@2x.png" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "etool16" - }, - "children": [ - { - "element": { - "name": "external_tools.png" - }, - "incompressible": true - }, - { - "element": { - "name": "external_tools@2x.png" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "obj16" - }, - "children": [ - { - "element": { - "name": "build_tab.png" - }, - "incompressible": true - }, - { - "element": { - "name": "build_tab@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "builder.png" - }, - "incompressible": true - }, - { - "element": { - "name": "builder@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "classpath.png" - }, - "incompressible": true - }, - { - "element": { - "name": "classpath@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "external_tools.png" - }, - "incompressible": true - }, - { - "element": { - "name": "external_tools@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "invalid_build_tool.png" - }, - "incompressible": true - }, - { - "element": { - "name": "invalid_build_tool@2x.png" - }, - "incompressible": true - }, - { - "element": { - "name": "main_tab.png" - }, - "incompressible": true - }, - { - "element": { - "name": "main_tab@2x.png" - }, - "incompressible": true - } - ] - }, - { - "element": { - "name": "wizban" - }, - "children": [ - { - "element": { - "name": "ext_tools_wiz.png" - }, - "incompressible": true - } - ] - } - ] - } - ] - }, - { - "element": { - "name": "plugin.properties" - }, - "incompressible": true - }, - { - "element": { - "name": "plugin.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "pom.xml" - }, - "incompressible": true - }, - { - "element": { - "name": "schema" - }, - "children": [ - { - "element": { - "name": "configurationDuplicationMaps.exsd" - }, - "incompressible": true - } - ] - } - ] - }, - { - "element": { - "name": "pom.xml" - }, - "incompressible": true - } - ] - } -] diff --git a/test/ui/tree/public/index.html b/test/ui/tree/public/index.html deleted file mode 100644 index 3f66d505016..00000000000 --- a/test/ui/tree/public/index.html +++ /dev/null @@ -1,403 +0,0 @@ - - - - - Tree - - - - - - - - - -
- - - - - - diff --git a/test/ui/tree/server.js b/test/ui/tree/server.js deleted file mode 100644 index 5b5dd3f1a6c..00000000000 --- a/test/ui/tree/server.js +++ /dev/null @@ -1,68 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -const fs = require('mz/fs'); -const path = require('path'); -const Koa = require('koa'); -const _ = require('koa-route'); -const serve = require('koa-static'); -const mount = require('koa-mount'); - -const app = new Koa(); -const root = path.dirname(path.dirname(__dirname)); - -async function getTree(fsPath, level) { - const element = path.basename(fsPath); - const stat = await fs.stat(fsPath); - - if (!stat.isDirectory() || element === '.git' || element === '.build' || level >= 4) { - return { element }; - } - - const childNames = await fs.readdir(fsPath); - const children = await Promise.all(childNames.map(async childName => await getTree(path.join(fsPath, childName), level + 1))); - return { element, collapsible: true, collapsed: false, children }; -} - -async function readdir(relativePath) { - const absolutePath = relativePath ? path.join(root, relativePath) : root; - const childNames = await fs.readdir(absolutePath); - const childStats = await Promise.all(childNames.map(async name => await fs.stat(path.join(absolutePath, name)))); - const result = []; - - for (let i = 0; i < childNames.length; i++) { - const name = childNames[i]; - const path = relativePath ? `${relativePath}/${name}` : name; - const stat = childStats[i]; - - if (stat.isFile()) { - result.push({ type: 'file', name, path }); - } else if (!stat.isDirectory() || name === '.git' || name === '.build') { - continue; - } else { - result.push({ type: 'dir', name, path }); - } - } - - return result; -} - -app.use(serve('public')); -app.use(mount('/static', serve('../../out'))); -app.use(_.get('/api/ls', async ctx => { - const relativePath = ctx.query.path; - const absolutePath = path.join(root, relativePath); - - ctx.body = await getTree(absolutePath, 0); -})); - -app.use(_.get('/api/readdir', async ctx => { - const relativePath = ctx.query.path; - - ctx.body = await readdir(relativePath); -})); - -app.listen(3000); -console.log('http://localhost:3000'); \ No newline at end of file diff --git a/test/ui/tree/tree.js b/test/ui/tree/tree.js deleted file mode 100644 index 4d5a9b5f271..00000000000 --- a/test/ui/tree/tree.js +++ /dev/null @@ -1,24 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -const path = require('path'); -const fs = require('fs'); - -function collect(location) { - const element = { name: path.basename(location) }; - const stat = fs.statSync(location); - - if (!stat.isDirectory()) { - return { element, incompressible: true }; - } - - const children = fs.readdirSync(location) - .map(child => path.join(location, child)) - .map(collect); - - return { element, children }; -} - -console.log(JSON.stringify(collect(process.cwd()))); \ No newline at end of file diff --git a/test/ui/tree/yarn.lock b/test/ui/tree/yarn.lock deleted file mode 100644 index 237201a684e..00000000000 --- a/test/ui/tree/yarn.lock +++ /dev/null @@ -1,341 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -accepts@^1.2.2: - version "1.3.5" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" - integrity sha1-63d99gEXI6OxTopywIBcjoZ0a9I= - dependencies: - mime-types "~2.1.18" - negotiator "0.6.1" - -any-promise@^1.0.0, any-promise@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" - integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= - -content-disposition@~0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" - integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= - -content-type@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== - -cookies@~0.7.0: - version "0.7.1" - resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.7.1.tgz#7c8a615f5481c61ab9f16c833731bcb8f663b99b" - integrity sha1-fIphX1SBxhq58WyDNzG8uPZjuZs= - dependencies: - depd "~1.1.1" - keygrip "~1.0.2" - -debug@*, debug@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - -debug@^2.6.1: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -deep-equal@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" - integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU= - -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= - -depd@^1.1.0, depd@~1.1.1, depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - -destroy@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - -error-inject@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/error-inject/-/error-inject-1.0.0.tgz#e2b3d91b54aed672f309d950d154850fa11d4f37" - integrity sha1-4rPZG1Su1nLzCdlQ0VSFD6EdTzc= - -escape-html@~1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= - -fresh@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= - -http-assert@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.3.0.tgz#a31a5cf88c873ecbb5796907d4d6f132e8c01e4a" - integrity sha1-oxpc+IyHPsu1eWkH1NbxMujAHko= - dependencies: - deep-equal "~1.0.1" - http-errors "~1.6.1" - -http-errors@^1.2.8, http-errors@^1.6.3, http-errors@~1.6.1, http-errors@~1.6.2: - version "1.6.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" - integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.0" - statuses ">= 1.4.0 < 2" - -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - -is-generator-function@^1.0.3: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522" - integrity sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw== - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= - -keygrip@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.2.tgz#ad3297c557069dea8bcfe7a4fa491b75c5ddeb91" - integrity sha1-rTKXxVcGneqLz+ek+kkbdcXd65E= - -koa-compose@^3.0.0, koa-compose@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-3.2.1.tgz#a85ccb40b7d986d8e5a345b3a1ace8eabcf54de7" - integrity sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec= - dependencies: - any-promise "^1.1.0" - -koa-compose@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877" - integrity sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw== - -koa-convert@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-1.2.0.tgz#da40875df49de0539098d1700b50820cebcd21d0" - integrity sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA= - dependencies: - co "^4.6.0" - koa-compose "^3.0.0" - -koa-is-json@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14" - integrity sha1-JzwH7c3Ljfaiwat9We52SRRR7BQ= - -koa-mount@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/koa-mount/-/koa-mount-3.0.0.tgz#08cab3b83d31442ed8b7e75c54b1abeb922ec197" - integrity sha1-CMqzuD0xRC7Yt+dcVLGr65IuwZc= - dependencies: - debug "^2.6.1" - koa-compose "^3.2.1" - -koa-route@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/koa-route/-/koa-route-3.2.0.tgz#76298b99a6bcfa9e38cab6fe5c79a8733e758bce" - integrity sha1-dimLmaa8+p44yrb+XHmocz51i84= - dependencies: - debug "*" - methods "~1.1.0" - path-to-regexp "^1.2.0" - -koa-send@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-5.0.0.tgz#5e8441e07ef55737734d7ced25b842e50646e7eb" - integrity sha512-90ZotV7t0p3uN9sRwW2D484rAaKIsD8tAVtypw/aBU+ryfV+fR2xrcAwhI8Wl6WRkojLUs/cB9SBSCuIb+IanQ== - dependencies: - debug "^3.1.0" - http-errors "^1.6.3" - mz "^2.7.0" - resolve-path "^1.4.0" - -koa-static@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/koa-static/-/koa-static-5.0.0.tgz#5e92fc96b537ad5219f425319c95b64772776943" - integrity sha512-UqyYyH5YEXaJrf9S8E23GoJFQZXkBVJ9zYYMPGz919MSX1KuvAcycIuS0ci150HCoPf4XQVhQ84Qf8xRPWxFaQ== - dependencies: - debug "^3.1.0" - koa-send "^5.0.0" - -koa@^2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/koa/-/koa-2.5.1.tgz#79f8b95f8d72d04fe9a58a8da5ebd6d341103f9c" - integrity sha512-cchwbMeG2dv3E2xTAmheDAuvR53tPgJZN/Hf1h7bTzJLSPcFZp8/t5+bNKJ6GaQZoydhZQ+1GNruhKdj3lIrug== - dependencies: - accepts "^1.2.2" - content-disposition "~0.5.0" - content-type "^1.0.0" - cookies "~0.7.0" - debug "*" - delegates "^1.0.0" - depd "^1.1.0" - destroy "^1.0.3" - error-inject "~1.0.0" - escape-html "~1.0.1" - fresh "^0.5.2" - http-assert "^1.1.0" - http-errors "^1.2.8" - is-generator-function "^1.0.3" - koa-compose "^4.0.0" - koa-convert "^1.2.0" - koa-is-json "^1.0.0" - mime-types "^2.0.7" - on-finished "^2.1.0" - only "0.0.2" - parseurl "^1.3.0" - statuses "^1.2.0" - type-is "^1.5.5" - vary "^1.0.0" - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= - -methods@~1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= - -mime-db@~1.33.0: - version "1.33.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" - integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ== - -mime-types@^2.0.7, mime-types@~2.1.18: - version "2.1.18" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" - integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ== - dependencies: - mime-db "~1.33.0" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -mz@^2.7.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" - integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== - dependencies: - any-promise "^1.0.0" - object-assign "^4.0.1" - thenify-all "^1.0.0" - -negotiator@0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" - integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= - -object-assign@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -on-finished@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= - dependencies: - ee-first "1.1.1" - -only@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" - integrity sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q= - -parseurl@^1.3.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" - integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M= - -path-is-absolute@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-to-regexp@^1.2.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" - integrity sha1-Wf3g9DW62suhA6hOnTvGTpa5k30= - dependencies: - isarray "0.0.1" - -resolve-path@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/resolve-path/-/resolve-path-1.4.0.tgz#c4bda9f5efb2fce65247873ab36bb4d834fe16f7" - integrity sha1-xL2p9e+y/OZSR4c6s2u02DT+Fvc= - dependencies: - http-errors "~1.6.2" - path-is-absolute "1.0.1" - -setprototypeof@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" - integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== - -"statuses@>= 1.4.0 < 2", statuses@^1.2.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - -thenify-all@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" - integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= - dependencies: - thenify ">= 3.1.0 < 4" - -"thenify@>= 3.1.0 < 4": - version "3.3.0" - resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.0.tgz#e69e38a1babe969b0108207978b9f62b88604839" - integrity sha1-5p44obq+lpsBCCB5eLn2K4hgSDk= - dependencies: - any-promise "^1.0.0" - -type-is@^1.5.5: - version "1.6.16" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" - integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.18" - -vary@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= From 28de0a46867c0df2bd31a31cbca1b6c52ddc4645 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru Date: Tue, 16 Feb 2021 11:59:32 +0100 Subject: [PATCH 194/325] Fix YAML typo --- build/azure-pipelines/product-compile.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/azure-pipelines/product-compile.yml b/build/azure-pipelines/product-compile.yml index 4f2024a6209..c51ed5644c6 100644 --- a/build/azure-pipelines/product-compile.yml +++ b/build/azure-pipelines/product-compile.yml @@ -140,4 +140,6 @@ steps: - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 displayName: "Component Detection" + inputs: + sourceScanPath: $(Build.SourcesDirectory) continueOnError: true From a1b9523db1077eb1fdf2dee97acd888abf132f2c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 16 Feb 2021 13:39:49 +0100 Subject: [PATCH 195/325] update my-work notebook --- .vscode/notebooks/my-work.github-issues | 48 +++++++++++++++---------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/.vscode/notebooks/my-work.github-issues b/.vscode/notebooks/my-work.github-issues index 1502c29db16..71847660727 100644 --- a/.vscode/notebooks/my-work.github-issues +++ b/.vscode/notebooks/my-work.github-issues @@ -3,114 +3,124 @@ "kind": 1, "language": "markdown", "value": "##### `Config`: This should be changed every month/milestone", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 2, "language": "github-issues", "value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog\n\n// current milestone name\n$milestone=milestone:\"February 2021\"", - "editable": true + "outputs": [] }, { "kind": 1, "language": "github-issues", "value": "## Milestone Work", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 2, "language": "github-issues", "value": "$repos $milestone assignee:@me is:open", - "editable": true + "outputs": [] }, { "kind": 1, "language": "github-issues", "value": "## Bugs, Debt, Features...", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 1, "language": "markdown", "value": "#### My Bugs", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 2, "language": "github-issues", "value": "$repos assignee:@me is:open label:bug", - "editable": true + "outputs": [] }, { "kind": 1, "language": "markdown", "value": "#### Debt & Engineering", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 2, "language": "github-issues", "value": "$repos assignee:@me is:open label:debt OR $repos assignee:@me is:open label:engineering", - "editable": true + "outputs": [] }, { "kind": 1, "language": "markdown", "value": "#### Performance 🐌 🔜 🏎", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 2, "language": "github-issues", "value": "$repos assignee:@me is:open label:perf OR $repos assignee:@me is:open label:perf-startup OR $repos assignee:@me is:open label:perf-bloat OR $repos assignee:@me is:open label:freeze-slow-crash-leak", - "editable": true + "outputs": [] }, { "kind": 1, "language": "markdown", "value": "#### Feature Requests", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 2, "language": "github-issues", "value": "$repos assignee:@me is:open label:feature-request milestone:Backlog sort:reactions-+1-desc", - "editable": true + "outputs": [] }, { "kind": 2, "language": "github-issues", "value": "$repos assignee:@me is:open milestone:\"Backlog Candidates\"", - "editable": true + "outputs": [] }, { "kind": 1, "language": "markdown", "value": "### Personal Inbox\n", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 1, "language": "markdown", "value": "\n#### Missing Type label", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 2, "language": "github-issues", "value": "$repos assignee:@me is:open type:issue -label:bug -label:\"needs more info\" -label:feature-request -label:under-discussion -label:debt -label:plan-item -label:upstream", - "editable": true + "outputs": [] }, { "kind": 1, "language": "markdown", "value": "#### Not Actionable", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 2, "language": "github-issues", "value": "$repos assignee:@me is:open label:\"needs more info\"", - "editable": true + "outputs": [] } ] \ No newline at end of file From d2cfc0792e04567b67c0d87575933f62a239cacd Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 16 Feb 2021 13:50:58 +0100 Subject: [PATCH 196/325] update editable state --- .vscode/notebooks/my-work.github-issues | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.vscode/notebooks/my-work.github-issues b/.vscode/notebooks/my-work.github-issues index 71847660727..c72d5cde062 100644 --- a/.vscode/notebooks/my-work.github-issues +++ b/.vscode/notebooks/my-work.github-issues @@ -10,6 +10,7 @@ "kind": 2, "language": "github-issues", "value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog\n\n// current milestone name\n$milestone=milestone:\"February 2021\"", + "editable": true, "outputs": [] }, { @@ -43,6 +44,7 @@ "kind": 2, "language": "github-issues", "value": "$repos assignee:@me is:open label:bug", + "editable": true, "outputs": [] }, { @@ -56,6 +58,7 @@ "kind": 2, "language": "github-issues", "value": "$repos assignee:@me is:open label:debt OR $repos assignee:@me is:open label:engineering", + "editable": true, "outputs": [] }, { @@ -69,6 +72,7 @@ "kind": 2, "language": "github-issues", "value": "$repos assignee:@me is:open label:perf OR $repos assignee:@me is:open label:perf-startup OR $repos assignee:@me is:open label:perf-bloat OR $repos assignee:@me is:open label:freeze-slow-crash-leak", + "editable": true, "outputs": [] }, { @@ -82,12 +86,14 @@ "kind": 2, "language": "github-issues", "value": "$repos assignee:@me is:open label:feature-request milestone:Backlog sort:reactions-+1-desc", + "editable": true, "outputs": [] }, { "kind": 2, "language": "github-issues", "value": "$repos assignee:@me is:open milestone:\"Backlog Candidates\"", + "editable": true, "outputs": [] }, { @@ -108,6 +114,7 @@ "kind": 2, "language": "github-issues", "value": "$repos assignee:@me is:open type:issue -label:bug -label:\"needs more info\" -label:feature-request -label:under-discussion -label:debt -label:plan-item -label:upstream", + "editable": true, "outputs": [] }, { @@ -121,6 +128,7 @@ "kind": 2, "language": "github-issues", "value": "$repos assignee:@me is:open label:\"needs more info\"", + "editable": true, "outputs": [] } ] \ No newline at end of file From 2ad3fe122412f392c1178eb7a850cd0c6ea51fa4 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 16 Feb 2021 14:30:18 +0100 Subject: [PATCH 197/325] storage - skip failing test --- .../storage/test/electron-main/storageMainService.test.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts index 4ed240e033b..cb3ae06d0fa 100644 --- a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts +++ b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts @@ -16,7 +16,7 @@ import { ILifecycleMainService, LifecycleMainPhase, ShutdownEvent, UnloadReason import { Emitter, Event } from 'vs/base/common/event'; import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; import { ICodeWindow } from 'vs/platform/windows/electron-main/windows'; -import { Promises, timeout } from 'vs/base/common/async'; +import { Promises } from 'vs/base/common/async'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; suite('StorageMainService (native)', function () { @@ -141,7 +141,7 @@ suite('StorageMainService (native)', function () { return testStorage(storageMainService.workspaceStorage(workspace), false); }); - test('storage closed onWillShutdown', async function () { + test.skip('storage closed onWillShutdown', async function () { const lifecycleMainService = new StorageTestLifecycleMainService(); const workspace = { id: generateUuid() }; const storageMainService = new TestStorageMainService(new NullLogService(), new NativeEnvironmentService(parseArgs(process.argv, OPTIONS)), lifecycleMainService, new TestConfigurationService()); @@ -162,7 +162,6 @@ suite('StorageMainService (native)', function () { await workspaceStorage.initialize(); - await timeout(0); await lifecycleMainService.fireOnWillShutdown(); strictEqual(didCloseGlobalStorage, true); From 04b7b5ee4c71d4895496dca6bb09185ba9734c03 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 16 Feb 2021 14:48:45 +0100 Subject: [PATCH 198/325] storage - let renderer close workspace DB --- src/vs/platform/storage/common/storageIpc.ts | 29 +++++++++++-------- .../storage/electron-main/storageIpc.ts | 12 ++++++++ 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/vs/platform/storage/common/storageIpc.ts b/src/vs/platform/storage/common/storageIpc.ts index fe88c0815c7..8ff562fc44f 100644 --- a/src/vs/platform/storage/common/storageIpc.ts +++ b/src/vs/platform/storage/common/storageIpc.ts @@ -29,9 +29,9 @@ export interface ISerializableItemsChangeEvent { abstract class BaseStorageDatabaseClient extends Disposable implements IStorageDatabase { - abstract onDidChangeItemsExternal: Event; + abstract readonly onDidChangeItemsExternal: Event; - constructor(protected channel: IChannel, private workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined) { + constructor(protected channel: IChannel, protected workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined) { super(); } @@ -56,16 +56,7 @@ abstract class BaseStorageDatabaseClient extends Disposable implements IStorageD return this.channel.call('updateItems', serializableRequest); } - async close(): Promise { - - // The database connection is not owned by us, but rather on the - // main side, as such we do not forward the close() request but - // let main side handle this properly via lifecycle methods. - // - // However, we cleanup our listeners because we are no longer - // interested in change events from the global database - this.dispose(); - } + abstract close(): Promise; } class GlobalStorageDatabaseClient extends BaseStorageDatabaseClient implements IStorageDatabase { @@ -91,6 +82,14 @@ class GlobalStorageDatabaseClient extends BaseStorageDatabaseClient implements I }); } } + + async close(): Promise { + + // The global storage database is shared across all instances so + // we do not await it. However we dispose the listener for external + // changes because we no longer interested int it. + this.dispose(); + } } class WorkspaceStorageDatabaseClient extends BaseStorageDatabaseClient implements IStorageDatabase { @@ -100,6 +99,12 @@ class WorkspaceStorageDatabaseClient extends BaseStorageDatabaseClient implement constructor(channel: IChannel, workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier) { super(channel, workspace); } + + async close(): Promise { + const serializableRequest: ISerializableUpdateRequest = { workspace: this.workspace }; + + return this.channel.call('close', serializableRequest); + } } export class StorageDatabaseChannelClient extends Disposable { diff --git a/src/vs/platform/storage/electron-main/storageIpc.ts b/src/vs/platform/storage/electron-main/storageIpc.ts index 2fb542e34cf..551953afbd0 100644 --- a/src/vs/platform/storage/electron-main/storageIpc.ts +++ b/src/vs/platform/storage/electron-main/storageIpc.ts @@ -104,6 +104,18 @@ export class StorageDatabaseChannel extends Disposable implements IServerChannel break; } + case 'close': { + + // We only allow to close workspace scoped storage because + // global storage is shared across all windows and closes + // only on shutdown. + if (workspace) { + return storage.close(); + } + + break; + } + default: throw new Error(`Call not found: ${command}`); } From 974b2143344d56d7728047b843a06b02e9942cc0 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 16 Feb 2021 14:31:15 +0100 Subject: [PATCH 199/325] rename: resolveNotebook is openNotebook --- src/vs/workbench/api/browser/mainThreadNotebook.ts | 6 +++--- src/vs/workbench/api/common/extHost.protocol.ts | 2 +- src/vs/workbench/api/common/extHostNotebook.ts | 2 +- .../contrib/notebook/browser/notebookServiceImpl.ts | 2 +- src/vs/workbench/contrib/notebook/common/notebookService.ts | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts index 5866a81d96a..b9ba768326d 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -480,7 +480,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo }, viewOptions: options.viewOptions, reloadNotebook: async (mainthreadTextModel: NotebookTextModel) => { - const data = await this._proxy.$resolveNotebookData(viewType, mainthreadTextModel.uri); + const data = await this._proxy.$openNotebook(viewType, mainthreadTextModel.uri); mainthreadTextModel.metadata = data.metadata; mainthreadTextModel.transientOptions = contentOptions; @@ -494,8 +494,8 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo }); }); }, - resolveNotebookDocument: async (viewType: string, uri: URI, backupId?: string) => { - const data = await this._proxy.$resolveNotebookData(viewType, uri, backupId); + openNotebook: async (viewType: string, uri: URI, backupId?: string) => { + const data = await this._proxy.$openNotebook(viewType, uri, backupId); return { data, transientOptions: contentOptions diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index d8dea657c6f..c2f4eed1aee 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1785,7 +1785,7 @@ export interface INotebookKernelInfoDto2 { } export interface ExtHostNotebookShape { - $resolveNotebookData(viewType: string, uri: UriComponents, backupId?: string): Promise; + $openNotebook(viewType: string, uri: UriComponents, backupId?: string): Promise; $resolveNotebookEditor(viewType: string, uri: UriComponents, editorId: string): Promise; $provideNotebookKernels(handle: number, uri: UriComponents, token: CancellationToken): Promise; $resolveNotebookKernel(handle: number, editorId: string, uri: UriComponents, kernelId: string, token: CancellationToken): Promise; diff --git a/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts index 6b995a33914..b58b4880b57 100644 --- a/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -442,7 +442,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN }); } - async $resolveNotebookData(viewType: string, uri: UriComponents, backupId?: string): Promise { + async $openNotebook(viewType: string, uri: UriComponents, backupId?: string): Promise { const provider = this._notebookContentProviders.get(viewType); if (!provider) { throw new Error(`NO provider for '${viewType}'`); diff --git a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts index 3aabfc323aa..5049ff03ab4 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts @@ -768,7 +768,7 @@ export class NotebookService extends Disposable implements INotebookService, ICu return notebookModel; } else { - const dataDto = await provider.controller.resolveNotebookDocument(viewType, uri, backupId); + const dataDto = await provider.controller.openNotebook(viewType, uri, backupId); let cells = dataDto.data.cells.length ? dataDto.data.cells : (uri.scheme === Schemas.untitled ? [{ cellKind: CellKind.Code, language: 'plaintext', //TODO@jrieken unsure what this is diff --git a/src/vs/workbench/contrib/notebook/common/notebookService.ts b/src/vs/workbench/contrib/notebook/common/notebookService.ts index b0faba9fcd8..c8cdc11f85a 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookService.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookService.ts @@ -23,7 +23,7 @@ export interface IMainNotebookController { supportBackup: boolean; viewOptions?: { displayName: string; filenamePattern: (string | IRelativePattern | INotebookExclusiveDocumentFilter)[]; exclusive: boolean; }; options: { transientOutputs: boolean; transientMetadata: TransientMetadata; }; - resolveNotebookDocument(viewType: string, uri: URI, backupId?: string): Promise<{ data: NotebookDataDto, transientOptions: TransientOptions; }>; + openNotebook(viewType: string, uri: URI, backupId?: string): Promise<{ data: NotebookDataDto, transientOptions: TransientOptions; }>; reloadNotebook(mainthreadTextModel: NotebookTextModel): Promise; resolveNotebookEditor(viewType: string, uri: URI, editorId: string): Promise; onDidReceiveMessage(editorId: string, rendererType: string | undefined, message: any): void; From 5fc7d91fb31d27ad58edc44d3456188638b81954 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 16 Feb 2021 15:00:17 +0100 Subject: [PATCH 200/325] workaround #116691 --- src/vs/workbench/services/log/electron-sandbox/logService.ts | 1 - src/vs/workbench/services/log/electron-sandbox/loggerService.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/workbench/services/log/electron-sandbox/logService.ts b/src/vs/workbench/services/log/electron-sandbox/logService.ts index d0fba0e728c..e9f19330624 100644 --- a/src/vs/workbench/services/log/electron-sandbox/logService.ts +++ b/src/vs/workbench/services/log/electron-sandbox/logService.ts @@ -37,5 +37,4 @@ export class NativeLogService extends LogService { this._register(disposables); } - } diff --git a/src/vs/workbench/services/log/electron-sandbox/loggerService.ts b/src/vs/workbench/services/log/electron-sandbox/loggerService.ts index 50795cdf780..fbe8bc70033 100644 --- a/src/vs/workbench/services/log/electron-sandbox/loggerService.ts +++ b/src/vs/workbench/services/log/electron-sandbox/loggerService.ts @@ -40,7 +40,7 @@ class Logger extends AbstractMessageLogger { loggerOptions?: ILoggerOptions, ) { super(loggerOptions?.always); - (this.file ? this.channel.call('createLogger', [file, loggerOptions]) : this.channel.call('createConsoleMainLogger', [file, loggerOptions])) + (this.file ? this.channel.call('createLogger', [file, loggerOptions]) : this.channel.call('createConsoleLogger', [file, loggerOptions])) .then(() => { this._log(this.buffer); this.isLoggerCreated = true; From 6b35ff74c14e665a0aa89b58775534390d71c6bd Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 16 Feb 2021 15:44:29 +0100 Subject: [PATCH 201/325] storage - bring back tests for close on shutdown --- src/vs/base/parts/storage/common/storage.ts | 9 +++++- .../electron-main/storageMainService.test.ts | 28 +++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/vs/base/parts/storage/common/storage.ts b/src/vs/base/parts/storage/common/storage.ts index 66023e7d651..a2c28e17070 100644 --- a/src/vs/base/parts/storage/common/storage.ts +++ b/src/vs/base/parts/storage/common/storage.ts @@ -84,7 +84,7 @@ export class Storage extends Disposable implements IStorage { private cache = new Map(); - private readonly flushDelayer = this._register(new ThrottledDelayer(Storage.DEFAULT_FLUSH_DELAY)); + private readonly flushDelayer = new ThrottledDelayer(Storage.DEFAULT_FLUSH_DELAY); private pendingDeletes = new Set(); private pendingInserts = new Map(); @@ -319,6 +319,13 @@ export class Storage extends Disposable implements IStorage { return new Promise(resolve => this.whenFlushedCallbacks.push(resolve)); } + + dispose(): void { + this.flushDelayer.cancel(); // workaround https://github.com/microsoft/vscode/issues/116777 + this.flushDelayer.dispose(); + + super.dispose(); + } } export class InMemoryStorageDatabase implements IStorageDatabase { diff --git a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts index cb3ae06d0fa..a0aa7f151d3 100644 --- a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts +++ b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts @@ -19,7 +19,7 @@ import { ICodeWindow } from 'vs/platform/windows/electron-main/windows'; import { Promises } from 'vs/base/common/async'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; -suite('StorageMainService (native)', function () { +suite('StorageMainService', function () { class TestStorageMainService extends StorageMainService { @@ -141,7 +141,7 @@ suite('StorageMainService (native)', function () { return testStorage(storageMainService.workspaceStorage(workspace), false); }); - test.skip('storage closed onWillShutdown', async function () { + test('storage closed onWillShutdown', async function () { const lifecycleMainService = new StorageTestLifecycleMainService(); const workspace = { id: generateUuid() }; const storageMainService = new TestStorageMainService(new NullLogService(), new NativeEnvironmentService(parseArgs(process.argv, OPTIONS)), lifecycleMainService, new TestConfigurationService()); @@ -160,6 +160,7 @@ suite('StorageMainService (native)', function () { strictEqual(workspaceStorage, storageMainService.workspaceStorage(workspace)); // same instance as long as not closed + await globalStorage.initialize(); await workspaceStorage.initialize(); await lifecycleMainService.fireOnWillShutdown(); @@ -172,4 +173,27 @@ suite('StorageMainService (native)', function () { return storage2.close(); }); + + test('storage closed before init works', async function () { + const storageMainService = new TestStorageMainService(new NullLogService(), new NativeEnvironmentService(parseArgs(process.argv, OPTIONS)), new StorageTestLifecycleMainService(), new TestConfigurationService()); + const workspace = { id: generateUuid() }; + + let workspaceStorage = storageMainService.workspaceStorage(workspace); + let didCloseWorkspaceStorage = false; + workspaceStorage.onDidCloseStorage(() => { + didCloseWorkspaceStorage = true; + }); + + let globalStorage1 = storageMainService.globalStorage; + let didCloseGlobalStorage = false; + globalStorage1.onDidCloseStorage(() => { + didCloseGlobalStorage = true; + }); + + await globalStorage1.close(); + await workspaceStorage.close(); + + strictEqual(didCloseGlobalStorage, true); + strictEqual(didCloseWorkspaceStorage, true); + }); }); From 8d9002679558432eca926b6bb4f767eaae6b1068 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 16 Feb 2021 15:50:18 +0100 Subject: [PATCH 202/325] set output and editable properties --- .vscode/notebooks/inbox.github-issues | 27 ++++++++++++++++------- .vscode/notebooks/papercuts.github-issues | 23 ++++++++++++------- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/.vscode/notebooks/inbox.github-issues b/.vscode/notebooks/inbox.github-issues index be0a2609cb2..69c1b7b0aa9 100644 --- a/.vscode/notebooks/inbox.github-issues +++ b/.vscode/notebooks/inbox.github-issues @@ -3,45 +3,56 @@ "kind": 1, "language": "markdown", "value": "## tl;dr: Triage Inbox\n\nAll inbox issues but not those that need more information. These issues need to be triaged, e.g assigned to a user or ask for more information", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 2, "language": "github-issues", - "value": "$inbox -label:\"needs more info\"" + "value": "$inbox -label:\"needs more info\"", + "editable": true, + "outputs": [] }, { "kind": 1, "language": "markdown", "value": "##### `Config`: defines the inbox query", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 2, "language": "github-issues", - "value": "$inbox=repo:microsoft/vscode is:open no:assignee -label:feature-request -label:testplan-item -label:plan-item " + "value": "$inbox=repo:microsoft/vscode is:open no:assignee -label:feature-request -label:testplan-item -label:plan-item ", + "editable": true, + "outputs": [] }, { "kind": 1, "language": "markdown", "value": "## Inbox tracking and Issue triage", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 1, "language": "markdown", "value": "New issues or pull requests submitted by the community are initially triaged by an [automatic classification bot](https://github.com/microsoft/vscode-github-triage-actions/tree/master/classifier-deep). Issues that the bot does not correctly triage are then triaged by a team member. The team rotates the inbox tracker on a weekly basis.\n\nA [mirror](https://github.com/JacksonKearl/testissues/issues) of the VS Code issue stream is available with details about how the bot classifies issues, including feature-area classifications and confidence ratings. Per-category confidence thresholds and feature-area ownership data is maintained in [.github/classifier.json](https://github.com/microsoft/vscode/blob/main/.github/classifier.json). \n\n💡 The bot is being run through a GitHub action that runs every 30 minutes. Give the bot the opportunity to classify an issue before doing it manually.\n\n### Inbox Tracking\n\nThe inbox tracker is responsible for the [global inbox](https://github.com/microsoft/vscode/issues?utf8=%E2%9C%93&q=is%3Aopen+no%3Aassignee+-label%3Afeature-request+-label%3Atestplan-item+-label%3Aplan-item) containing all **open issues and pull requests** that\n- are neither **feature requests** nor **test plan items** nor **plan items** and\n- have **no owner assignment**.\n\nThe **inbox tracker** may perform any step described in our [issue triaging documentation](https://github.com/microsoft/vscode/wiki/Issues-Triaging) but its main responsibility is to route issues to the actual feature area owner.\n\nFeature area owners track the **feature area inbox** containing all **open issues and pull requests** that\n- are personally assigned to them and are not assigned to any milestone\n- are labeled with their feature area label and are not assigned to any milestone.\nThis secondary triage may involve any of the steps described in our [issue triaging documentation](https://github.com/microsoft/vscode/wiki/Issues-Triaging) and results in a fully triaged or closed issue.\n\nThe [github triage extension](https://github.com/microsoft/vscode-github-triage-extension) can be used to assist with triaging — it provides a \"Command Palette\"-style list of triaging actions like assignment, labeling, and triggers for various bot actions.", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 1, "language": "markdown", "value": "## All Inbox Items\n\nAll issues that have no assignee and that have neither **feature requests** nor **test plan items** nor **plan items**.", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 2, "language": "github-issues", - "value": "$inbox" + "value": "$inbox", + "editable": true, + "outputs": [] } ] \ No newline at end of file diff --git a/.vscode/notebooks/papercuts.github-issues b/.vscode/notebooks/papercuts.github-issues index 4da4734ce5d..01bb21518fc 100644 --- a/.vscode/notebooks/papercuts.github-issues +++ b/.vscode/notebooks/papercuts.github-issues @@ -3,42 +3,49 @@ "kind": 1, "language": "markdown", "value": "## Papercuts\n\nThis notebook serves as an ongoing collection of papercut issues that we encounter while dogfooding. With that in mind only promote issues that really turn you off, e.g. issues that make you want to stop using VS Code or its extensions. To mark an issue (bug, feature-request, etc.) as papercut add the labels: `papercut :drop_of_blood:`", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 1, "language": "markdown", "value": "## All Papercuts\n\nThese are all papercut issues that we encounter while dogfooding vscode or extensions that we author.", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 2, "language": "github-issues", "value": "repo:microsoft/vscode is:open -label:notebook label:\"papercut :drop_of_blood:\"", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 1, "language": "markdown", "value": "## Native Notebook", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 2, "language": "github-issues", "value": "repo:microsoft/vscode is:open label:notebook label:\"papercut :drop_of_blood:\"", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 1, "language": "markdown", "value": "### My Papercuts", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 2, "language": "github-issues", "value": "repo:microsoft/vscode is:open assignee:@me label:\"papercut :drop_of_blood:\"", - "editable": true + "editable": true, + "outputs": [] } -] +] \ No newline at end of file From c9607e61e0fe8850de2b2b276234d719c8ce6ce7 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 16 Feb 2021 16:15:26 +0100 Subject: [PATCH 203/325] actionBar: always respect orientation, so only left / right navgiate in horizontal and up/down in vertical --- src/vs/base/browser/ui/actionbar/actionbar.ts | 18 ++++++++---------- src/vs/base/browser/ui/menu/menu.ts | 1 - src/vs/base/browser/ui/toolbar/toolbar.ts | 2 -- .../workbench/browser/parts/views/treeView.ts | 3 +-- .../contrib/debug/browser/breakpointsView.ts | 6 +++--- .../contrib/debug/browser/callStackView.ts | 7 +++---- .../extensions/browser/extensionsList.ts | 3 +-- .../files/browser/views/openEditorsView.ts | 4 ++-- .../markers/browser/markersTreeViewer.ts | 3 +-- .../notebook/browser/diff/diffComponents.ts | 3 +-- .../browser/diff/notebookTextDiffList.ts | 3 +-- .../browser/view/renderers/cellRenderer.ts | 9 +++------ .../preferences/browser/settingsTree.ts | 1 - .../preferences/browser/settingsWidgets.ts | 2 +- .../contrib/remote/browser/tunnelView.ts | 3 +-- .../scm/browser/scmRepositoryRenderer.ts | 2 +- .../contrib/scm/browser/scmViewPane.ts | 5 ++--- .../search/browser/searchResultsView.ts | 6 +++--- .../testing/browser/testingExplorerView.ts | 3 +-- 19 files changed, 33 insertions(+), 51 deletions(-) diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index 83135785546..0dd80a02478 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -35,8 +35,6 @@ export interface IActionBarOptions { readonly triggerKeys?: ActionTrigger; readonly allowContextMenu?: boolean; readonly preventLoopNavigation?: boolean; - // Pass true here when the up and down keys should not be eaten up by the ActionBar. For example, when an ActionBar is in the list. - readonly respectOrientationForPreviousAndNextKey?: boolean; } export interface IActionOptions extends IActionViewItemOptions { @@ -120,22 +118,22 @@ export class ActionBar extends Disposable implements IActionRunner { switch (this._orientation) { case ActionsOrientation.HORIZONTAL: - previousKeys = this.options.respectOrientationForPreviousAndNextKey ? [KeyCode.LeftArrow] : [KeyCode.LeftArrow, KeyCode.UpArrow]; - nextKeys = this.options.respectOrientationForPreviousAndNextKey ? [KeyCode.RightArrow] : [KeyCode.RightArrow, KeyCode.DownArrow]; + previousKeys = [KeyCode.LeftArrow]; + nextKeys = [KeyCode.RightArrow]; break; case ActionsOrientation.HORIZONTAL_REVERSE: - previousKeys = this.options.respectOrientationForPreviousAndNextKey ? [KeyCode.RightArrow] : [KeyCode.RightArrow, KeyCode.DownArrow]; - nextKeys = this.options.respectOrientationForPreviousAndNextKey ? [KeyCode.LeftArrow] : [KeyCode.LeftArrow, KeyCode.UpArrow]; + previousKeys = [KeyCode.RightArrow]; + nextKeys = [KeyCode.LeftArrow]; this.domNode.className += ' reverse'; break; case ActionsOrientation.VERTICAL: - previousKeys = this.options.respectOrientationForPreviousAndNextKey ? [KeyCode.UpArrow] : [KeyCode.LeftArrow, KeyCode.UpArrow]; - nextKeys = this.options.respectOrientationForPreviousAndNextKey ? [KeyCode.DownArrow] : [KeyCode.RightArrow, KeyCode.DownArrow]; + previousKeys = [KeyCode.UpArrow]; + nextKeys = [KeyCode.DownArrow]; this.domNode.className += ' vertical'; break; case ActionsOrientation.VERTICAL_REVERSE: - previousKeys = this.options.respectOrientationForPreviousAndNextKey ? [KeyCode.DownArrow] : [KeyCode.RightArrow, KeyCode.DownArrow]; - nextKeys = this.options.respectOrientationForPreviousAndNextKey ? [KeyCode.UpArrow] : [KeyCode.LeftArrow, KeyCode.UpArrow]; + previousKeys = [KeyCode.DownArrow]; + nextKeys = [KeyCode.UpArrow]; this.domNode.className += ' vertical reverse'; break; } diff --git a/src/vs/base/browser/ui/menu/menu.ts b/src/vs/base/browser/ui/menu/menu.ts index 9a9132359ce..025428f4046 100644 --- a/src/vs/base/browser/ui/menu/menu.ts +++ b/src/vs/base/browser/ui/menu/menu.ts @@ -86,7 +86,6 @@ export class Menu extends ActionBar { context: options.context, actionRunner: options.actionRunner, ariaLabel: options.ariaLabel, - respectOrientationForPreviousAndNextKey: true, triggerKeys: { keys: [KeyCode.Enter, ...(isMacintosh || isLinux ? [KeyCode.Space] : [])], keyDown: true } }); diff --git a/src/vs/base/browser/ui/toolbar/toolbar.ts b/src/vs/base/browser/ui/toolbar/toolbar.ts index 3b91ffa5573..c1348a93ddc 100644 --- a/src/vs/base/browser/ui/toolbar/toolbar.ts +++ b/src/vs/base/browser/ui/toolbar/toolbar.ts @@ -28,7 +28,6 @@ export interface IToolBarOptions { anchorAlignmentProvider?: () => AnchorAlignment; renderDropdownAsChildElement?: boolean; moreIcon?: CSSIcon; - readonly respectOrientationForPreviousAndNextKey?: boolean; } /** @@ -64,7 +63,6 @@ export class ToolBar extends Disposable { orientation: options.orientation, ariaLabel: options.ariaLabel, actionRunner: options.actionRunner, - respectOrientationForPreviousAndNextKey: options.respectOrientationForPreviousAndNextKey, actionViewItemProvider: (action: IAction) => { if (action.id === ToggleMenuAction.ID) { this.toggleMenuActionViewItem = new DropdownMenuActionViewItem( diff --git a/src/vs/workbench/browser/parts/views/treeView.ts b/src/vs/workbench/browser/parts/views/treeView.ts index f8961757153..9c49ffdcca2 100644 --- a/src/vs/workbench/browser/parts/views/treeView.ts +++ b/src/vs/workbench/browser/parts/views/treeView.ts @@ -873,8 +873,7 @@ class TreeRenderer extends Disposable implements ITreeRenderer { return action.createActionViewItem(); } return new ExtensionActionViewItem(null, action, actionOptions); - }, - respectOrientationForPreviousAndNextKey: true + } }); actionbar.onDidRun(({ error }) => error && this.notificationService.error(error)); diff --git a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts index 9936ef5a754..e54534fd378 100644 --- a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts @@ -537,7 +537,7 @@ class EditorGroupRenderer implements IListRenderer action.id === QuickFixAction.ID ? _instantiationService.createInstance(QuickFixActionViewItem, action) : undefined, - respectOrientationForPreviousAndNextKey: true + actionViewItemProvider: (action: IAction) => action.id === QuickFixAction.ID ? _instantiationService.createInstance(QuickFixActionViewItem, action) : undefined })); this.icon = dom.append(parent, dom.$('')); this.multilineActionbar = this._register(new ActionBar(dom.append(parent, dom.$('.multiline-actions')), { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 24f880fbabf..235dd429996 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -150,8 +150,7 @@ class PropertyHeader extends Disposable { } return undefined; - }, - respectOrientationForPreviousAndNextKey: true + } }); this._register(this._toolbar); this._toolbar.context = { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts index e25db2f37b0..ce2bc9c6ec2 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts @@ -188,8 +188,7 @@ export class CellDiffSideBySideRenderer implements IListRenderer extends Dispo rowElement.setAttribute('tabindex', item.selected ? '0' : '-1'); rowElement.classList.toggle('selected', item.selected); - const actionBar = new ActionBar(rowElement, { respectOrientationForPreviousAndNextKey: true }); + const actionBar = new ActionBar(rowElement); this.listDisposables.add(actionBar); actionBar.push(this.getActionsForItem(item, idx), { icon: true, label: true }); diff --git a/src/vs/workbench/contrib/remote/browser/tunnelView.ts b/src/vs/workbench/contrib/remote/browser/tunnelView.ts index 02b75df99e9..daa3fba23f9 100644 --- a/src/vs/workbench/contrib/remote/browser/tunnelView.ts +++ b/src/vs/workbench/contrib/remote/browser/tunnelView.ts @@ -225,8 +225,7 @@ class TunnelTreeRenderer extends Disposable implements ITreeRenderer action instanceof MenuItemAction ? this.instantiationService.createInstance(MenuEntryActionViewItem, action) - : undefined, - respectOrientationForPreviousAndNextKey: true + : undefined }); return { label, actionBar, icon }; From e537fd9e3182ec03cf26d195fc17b184715628ec Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Tue, 16 Feb 2021 16:31:33 +0100 Subject: [PATCH 204/325] first cut of proposed "inline values provider" API --- src/vs/editor/common/modes.ts | 81 +++++++++- src/vs/vscode.proposed.d.ts | 143 +++++++++++++++++- .../api/browser/mainThreadLanguageFeatures.ts | 25 +++ .../workbench/api/common/extHost.api.impl.ts | 7 + .../workbench/api/common/extHost.protocol.ts | 7 + .../api/common/extHostApiCommands.ts | 8 + .../api/common/extHostLanguageFeatures.ts | 42 ++++- .../api/common/extHostTypeConverters.ts | 60 ++++++++ src/vs/workbench/api/common/extHostTypes.ts | 45 ++++++ .../debug/browser/debugEditorContribution.ts | 90 +++++++++-- 10 files changed, 487 insertions(+), 21 deletions(-) diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index f4b946213dd..3731b7dee38 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -266,7 +266,7 @@ export interface HoverProvider { } /** - * An evaluatable expression represents additional information for an expression in a document. Evaluatable expression are + * An evaluatable expression represents additional information for an expression in a document. Evaluatable expressions are * evaluated by a debugger or runtime and their result is rendered in a tooltip-like widget. * @internal */ @@ -275,15 +275,16 @@ export interface EvaluatableExpression { * The range to which this expression applies. */ range: IRange; - /* + /** * This expression overrides the expression extracted from the range. */ expression?: string; } + /** - * The hover provider interface defines the contract between extensions and - * the [hover](https://code.visualstudio.com/docs/editor/intellisense)-feature. + * The evaluatable expression provider interface defines the contract between extensions and + * the debug hover. * @internal */ export interface EvaluatableExpressionProvider { @@ -295,6 +296,73 @@ export interface EvaluatableExpressionProvider { provideEvaluatableExpression(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult; } +/** + * An open ended information bag passed to the inline value provider. + * A minimal context containes just the document location where the debugger has stopped. + * @internal + */ +export interface InlineValueContext { + stoppedLocation: Range; +} + +/** + * Provide inline value as text. + * @internal + */ +export interface InlineValueText { + type: 'text'; + text: string; + range: IRange; +} + +/** + * Provide inline value through a variable lookup. + * @internal + */ +export interface InlineValueVariableLookup { + type: 'variable'; + variableName: string; + caseSensitiveLookup: boolean; + range: IRange; +} + +/** + * Provide inline value through an expression evaluation. + * @internal + */ +export interface InlineValueExpression { + type: 'expression'; + expression: string; + range: IRange; +} + +/** + * Inline value information can be provided by different means: + * - directly as a text value (class InlineValueText). + * - as a name to use for a variable lookup (class InlineValueVariableLookup) + * - as an evaluatable expression (class InlineValueEvaluatableExpression) + * The InlineValue types combines all inline value types into one type. + * @internal + */ +export type InlineValue = InlineValueText | InlineValueVariableLookup | InlineValueExpression; + +/** + * The inline values provider interface defines the contract between extensions and + * the debugger's inline values feature. + * @internal + */ +export interface InlineValuesProvider { + /** + */ + onDidChangeInlineValues?: Event | undefined; + /** + * Provide the "inline values" for the given range and document. Multiple hovers at the same + * position will be merged by the editor. A hover can have a range which defaults + * to the word range at the position when omitted. + */ + provideInlineValues(model: model.ITextModel, viewPort: Range, context: InlineValueContext, token: CancellationToken): ProviderResult; +} + export const enum CompletionItemKind { Method, Function, @@ -1745,6 +1813,11 @@ export const HoverProviderRegistry = new LanguageFeatureRegistry( */ export const EvaluatableExpressionProviderRegistry = new LanguageFeatureRegistry(); +/** + * @internal + */ +export const InlineValuesProviderRegistry = new LanguageFeatureRegistry(); + /** * @internal */ diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 6bd29a1c0f9..341b5b78df6 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -734,8 +734,149 @@ declare module 'vscode' { //#endregion + //#region inline value provider: https://github.com/microsoft/vscode/issues/105690 + + /** + * The inline values provider interface defines the contract between extensions and the VS Code debugger inline values feature. + * In this contract the provider returns inline value information for a given document range + * and VS Code shows this information in the editor at the end of lines. + */ + export interface InlineValuesProvider { + + /** + * An optional event to signal that inline values have changed. + * @see [EventEmitter](#EventEmitter) + */ + onDidChangeInlineValues?: Event | undefined; + + /** + * Provide "inline value" information for a given document and range. + * VS Code calls this method whenever debugging stops in the given document. + * The returned inline values information is rendered in the editor at the end of lines. + * + * @param document The document for which the inline values information is needed. + * @param viewPort The visible document range for which inline values should be computed. + * @param context A bag containing contextual information like the current location. + * @param token A cancellation token. + * @return An array of InlineValueDescriptors or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideInlineValues(document: TextDocument, viewPort: Range, context: InlineValueContext, token: CancellationToken): ProviderResult; + } + + /** + * An open ended information bag passed to the inline value provider. + * A minimal context containes just the document location where the debugger has stopped. + * Additional optional information might be scope information or variables and their values. + */ + export interface InlineValueContext { + /** + * The document range where execution has stopped. + * Typically the end position of the range denotes the line where the inline values are shown. + */ + stoppedLocation: Range; + + // ... more to come, e.g. Scope information or variable/value candidate information + } + + /** + * Inline value information can be provided by different means: + * - directly as a text value (class InlineValueText). + * - as a name to use for a variable lookup (class InlineValueVariableLookup) + * - as an evaluatable expression (class InlineValueEvaluatableExpression) + * The InlineValue types combines all inline value types into one type. + */ + export type InlineValue = InlineValueText | InlineValueVariableLookup | InlineValueEvaluatableExpression; + + /** + * Provide inline value as text. + */ + export class InlineValueText { + /** + * The text of the inline value. + */ + readonly text: string; + /** + * The range of the inline value. + */ + readonly range: Range; + /** + * Creates a new InlineValueText object. + * + * @param text The value to be shown for the line. + * @param range The document line where to show the inline value. + */ + constructor(text: string, range: Range); + } + + /** + * Provide inline value through a variable lookup. + */ + export class InlineValueVariableLookup { + /** + * The name of the variable to look up. + */ + readonly variableName: string; + /** + * How to perform the lookup. + */ + readonly caseSensitiveLookup: boolean; + /** + * The range of the inline value. + */ + readonly range: Range; + /** + * Creates a new InlineValueVariableLookup object. + * + * @param variableName The name of the variable to look up. + * @param range The document line where to show the inline value. + * @param caseSensitiveLookup How to perform the lookup. If missing lookup is case sensitive. + */ + constructor(variableName: string, range: Range, caseSensitiveLookup?: boolean); + } + + /** + * Provide inline value through an expression evaluation. + */ + export class InlineValueEvaluatableExpression { + /** + * The expression to evaluate. + */ + readonly expression: string; + /** + * The range of the inline value. + */ + readonly range: Range; + /** + * Creates a new InlineValueEvaluatableExpression object. + * + * @param expression The expression to evaluate. + * @param range The document line where to show the inline value. + */ + constructor(expression: string, range: Range); + } + + export namespace languages { + + /** + * Register a provider that returns inline values for text documents. + * If debugging has stopped VS Code shows inline values in the editor at the end of lines. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider An inline values provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerInlineValuesProvider(selector: DocumentSelector, provider: InlineValuesProvider): Disposable; + } + + //#endregion + // eslint-disable-next-line vscode-dts-region-comments - //#region debug + //#region @weinand: variables view action contributions /** * A DebugProtocolVariableContainer is an opaque stand-in type for the intersection of the Scope and Variable types defined in the Debug Adapter Protocol. diff --git a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index 04d6dfed752..fd83c6e81a0 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -250,6 +250,31 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha })); } + // --- inline values + + $registerInlineValuesProvider(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void { + const provider = { + provideInlineValues: (model: ITextModel, viewPort: EditorRange, context: modes.InlineValueContext, token: CancellationToken): Promise => { + return this._proxy.$provideInlineValues(handle, model.uri, viewPort, context, token); + } + }; + + if (typeof eventHandle === 'number') { + const emitter = new Emitter(); + this._registrations.set(eventHandle, emitter); + provider.onDidChangeInlineValues = emitter.event; + } + + this._registrations.set(handle, modes.InlineValuesProviderRegistry.register(selector, provider)); + } + + $emitInlineValuesEvent(eventHandle: number, event?: any): void { + const obj = this._registrations.get(eventHandle); + if (obj instanceof Emitter) { + obj.fire(event); + } + } + // --- occurrences $registerDocumentHighlightProvider(handle: number, selector: IDocumentFilterDto[]): void { diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index b9bacd2d7f6..45af435ed3d 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -409,6 +409,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I registerEvaluatableExpressionProvider(selector: vscode.DocumentSelector, provider: vscode.EvaluatableExpressionProvider): vscode.Disposable { return extHostLanguageFeatures.registerEvaluatableExpressionProvider(extension, checkSelector(selector), provider, extension.identifier); }, + registerInlineValuesProvider(selector: vscode.DocumentSelector, provider: vscode.InlineValuesProvider): vscode.Disposable { + checkProposedApiEnabled(extension); + return extHostLanguageFeatures.registerInlineValuesProvider(extension, checkSelector(selector), provider, extension.identifier); + }, registerDocumentHighlightProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable { return extHostLanguageFeatures.registerDocumentHighlightProvider(extension, checkSelector(selector), provider); }, @@ -1165,6 +1169,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I EndOfLine: extHostTypes.EndOfLine, EnvironmentVariableMutatorType: extHostTypes.EnvironmentVariableMutatorType, EvaluatableExpression: extHostTypes.EvaluatableExpression, + InlineValueText: extHostTypes.InlineValueText, + InlineValueVariableLookup: extHostTypes.InlineValueVariableLookup, + InlineValueEvaluatableExpression: extHostTypes.InlineValueEvaluatableExpression, EventEmitter: Emitter, ExtensionKind: extHostTypes.ExtensionKind, ExtensionMode: extHostTypes.ExtensionMode, diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index c2f4eed1aee..ceef2474341 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -378,6 +378,8 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable { $registerTypeDefinitionSupport(handle: number, selector: IDocumentFilterDto[]): void; $registerHoverProvider(handle: number, selector: IDocumentFilterDto[]): void; $registerEvaluatableExpressionProvider(handle: number, selector: IDocumentFilterDto[]): void; + $registerInlineValuesProvider(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void; + $emitInlineValuesEvent(eventHandle: number, event?: any): void; $registerDocumentHighlightProvider(handle: number, selector: IDocumentFilterDto[]): void; $registerLinkedEditingRangeProvider(handle: number, selector: IDocumentFilterDto[]): void; $registerReferenceSupport(handle: number, selector: IDocumentFilterDto[]): void; @@ -1466,6 +1468,10 @@ export interface ILinkedEditingRangesDto { wordPattern?: IRegExpDto; } +export interface IInlineValueContextDto { + stoppedLocation: IRange; +} + export interface ExtHostLanguageFeaturesShape { $provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise; $provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise; @@ -1477,6 +1483,7 @@ export interface ExtHostLanguageFeaturesShape { $provideTypeDefinition(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; $provideHover(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; $provideEvaluatableExpression(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; + $provideInlineValues(handle: number, resource: UriComponents, range: IRange, context: modes.InlineValueContext, token: CancellationToken): Promise; $provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; $provideLinkedEditingRanges(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; $provideReferences(handle: number, resource: UriComponents, position: IPosition, context: modes.ReferenceContext, token: CancellationToken): Promise; diff --git a/src/vs/workbench/api/common/extHostApiCommands.ts b/src/vs/workbench/api/common/extHostApiCommands.ts index 93f77a9576d..6bdfa6fb2b4 100644 --- a/src/vs/workbench/api/common/extHostApiCommands.ts +++ b/src/vs/workbench/api/common/extHostApiCommands.ts @@ -359,6 +359,14 @@ const newCommands: ApiCommand[] = [ }; })) ), + // --- debug support + new ApiCommand( + 'vscode.executeInlineValueProvider', '_executeInlineValueProvider', 'Execute inline value provider', + [ApiCommandArgument.Uri, ApiCommandArgument.Range], + new ApiCommandResult('A promise that resolves to an array of InlineValue objects', result => { + return result.map(typeConverters.InlineValue.to); + }) + ), // --- open'ish commands new ApiCommand( 'vscode.open', '_workbench.open', 'Opens the provided resource in the editor. Can be a text or binary file, or a http(s) url. If you need more control over the options for opening a text file, use vscode.window.showTextDocument instead.', diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index 34ca106504d..5d96d713260 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -291,6 +291,24 @@ class EvaluatableExpressionAdapter { } } +class InlineValuesAdapter { + + constructor( + private readonly _documents: ExtHostDocuments, + private readonly _provider: vscode.InlineValuesProvider, + ) { } + + public provideInlineValues(resource: URI, viewPort: IRange, context: extHostProtocol.IInlineValueContextDto, token: CancellationToken): Promise { + const doc = this._documents.getDocument(resource); + return asPromise(() => this._provider.provideInlineValues(doc, typeConvert.Range.to(viewPort), typeConvert.InlineValueContext.to(context), token)).then(value => { + if (Array.isArray(value)) { + return value.map(iv => typeConvert.InlineValue.from(iv)); + } + return undefined; + }); + } +} + class DocumentHighlightAdapter { constructor( @@ -1334,7 +1352,8 @@ type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | Hov | RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter | SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter | TypeDefinitionAdapter | ColorProviderAdapter | FoldingProviderAdapter | DeclarationAdapter - | SelectionRangeAdapter | CallHierarchyAdapter | DocumentSemanticTokensAdapter | DocumentRangeSemanticTokensAdapter | EvaluatableExpressionAdapter + | SelectionRangeAdapter | CallHierarchyAdapter | DocumentSemanticTokensAdapter | DocumentRangeSemanticTokensAdapter + | EvaluatableExpressionAdapter | InlineValuesAdapter | LinkedEditingRangeAdapter | InlineHintsAdapter; class AdapterData { @@ -1568,6 +1587,27 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF return this._withAdapter(handle, EvaluatableExpressionAdapter, adapter => adapter.provideEvaluatableExpression(URI.revive(resource), position, token), undefined); } + // --- debug inline values + + registerInlineValuesProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.InlineValuesProvider, extensionId?: ExtensionIdentifier): vscode.Disposable { + + const eventHandle = typeof provider.onDidChangeInlineValues === 'function' ? this._nextHandle() : undefined; + const handle = this._addNewAdapter(new InlineValuesAdapter(this._documents, provider), extension); + + this._proxy.$registerInlineValuesProvider(handle, this._transformDocumentSelector(selector), eventHandle); + let result = this._createDisposable(handle); + + if (eventHandle !== undefined) { + const subscription = provider.onDidChangeInlineValues!(_ => this._proxy.$emitInlineValuesEvent(eventHandle)); + result = Disposable.from(result, subscription); + } + return result; + } + + $provideInlineValues(handle: number, resource: UriComponents, range: IRange, context: extHostProtocol.IInlineValueContextDto, token: CancellationToken): Promise { + return this._withAdapter(handle, InlineValuesAdapter, adapter => adapter.provideInlineValues(URI.revive(resource), range, context, token), undefined); + } + // --- occurrences registerDocumentHighlightProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable { diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 910683b56be..d3afe4eb214 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -850,6 +850,66 @@ export namespace EvaluatableExpression { } } +export namespace InlineValue { + export function from(inlineValue: vscode.InlineValue): modes.InlineValue { + if (inlineValue instanceof types.InlineValueText) { + return { + type: 'text', + text: inlineValue.text, + range: Range.from(inlineValue.range) + }; + } else if (inlineValue instanceof types.InlineValueVariableLookup) { + return { + type: 'variable', + variableName: inlineValue.variableName, + caseSensitiveLookup: inlineValue.caseSensitiveLookup, + range: Range.from(inlineValue.range) + }; + } else if (inlineValue instanceof types.InlineValueEvaluatableExpression) { + return { + type: 'expression', + expression: inlineValue.expression, + range: Range.from(inlineValue.range) + }; + } else { + throw new Error(`Unknown 'InlineValue' type`); + } + } + + export function to(inlineValue: modes.InlineValue): vscode.InlineValue { + switch (inlineValue.type) { + case 'text': + return { + text: inlineValue.text, + range: Range.to(inlineValue.range) + }; + case 'variable': + return { + variableName: inlineValue.variableName, + caseSensitiveLookup: inlineValue.caseSensitiveLookup, + range: Range.to(inlineValue.range) + }; + case 'expression': + return { + expression: inlineValue.expression, + range: Range.to(inlineValue.range) + }; + } + } +} + +export namespace InlineValueContext { + export function from(inlineValueContext: vscode.InlineValueContext): extHostProtocol.IInlineValueContextDto { + return { + stoppedLocation: Range.from(inlineValueContext.stoppedLocation) + }; + } + + export function to(inlineValueContext: extHostProtocol.IInlineValueContextDto): types.InlineValueContext { + return new types.InlineValueContext(Range.to(inlineValueContext.stoppedLocation)); + } +} + export namespace DocumentHighlight { export function from(documentHighlight: vscode.DocumentHighlight): modes.DocumentHighlight { return { diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 9bc85fa2ace..c815d8322af 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -2439,6 +2439,51 @@ export class EvaluatableExpression implements vscode.EvaluatableExpression { } } +@es5ClassCompat +export class InlineValueText implements vscode.InlineValueText { + readonly range: Range; + readonly text: string; + + constructor(text: string, range: Range) { + this.text = text; + this.range = range; + } +} + +@es5ClassCompat +export class InlineValueVariableLookup implements vscode.InlineValueVariableLookup { + readonly variableName: string; + readonly caseSensitiveLookup: boolean; + readonly range: Range; + + constructor(variableName: string, range: Range, caseSensitiveLookup: boolean) { + this.variableName = variableName; + this.caseSensitiveLookup = caseSensitiveLookup; + this.range = range; + } +} + +@es5ClassCompat +export class InlineValueEvaluatableExpression implements vscode.InlineValueEvaluatableExpression { + readonly expression: string; + readonly range: Range; + + constructor(expression: string, range: Range) { + this.expression = expression; + this.range = range; + } +} + +@es5ClassCompat +export class InlineValueContext implements vscode.InlineValueContext { + + readonly stoppedLocation: vscode.Range; + + constructor(range: vscode.Range) { + this.stoppedLocation = range; + } +} + //#region file api export enum FileChangeType { diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts index f3fa36a2c2e..346d7c395aa 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts @@ -11,7 +11,10 @@ import { setProperty } from 'vs/base/common/jsonEdit'; import { Constants } from 'vs/base/common/uint'; import { KeyCode } from 'vs/base/common/keyCodes'; import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { StandardTokenType } from 'vs/editor/common/modes'; +import { InlineValuesProviderRegistry, StandardTokenType } from 'vs/editor/common/modes'; +import { CancellationTokenSource } from 'vs/base/common/cancellation'; +import { flatten } from 'vs/base/common/arrays'; +import { onUnexpectedExternalError } from 'vs/base/common/errors'; import { DEFAULT_WORD_REGEXP } from 'vs/editor/common/model/wordHelper'; import { ICodeEditor, IEditorMouseEvent, MouseTargetType, IPartialEditorMouseEvent } from 'vs/editor/browser/editorBrowser'; import { IDecorationOptions } from 'vs/editor/common/editorCommon'; @@ -47,7 +50,7 @@ const MAX_NUM_INLINE_VALUES = 100; // JS Global scope can have 700+ entries. We const MAX_INLINE_DECORATOR_LENGTH = 150; // Max string length of each inline decorator when debugging. If exceeded ... is added const MAX_TOKENIZATION_LINE_LEN = 500; // If line is too long, then inline values for the line are skipped -function createInlineValueDecoration(lineNumber: number, contentText: string): IDecorationOptions { +function createInlineValueDecoration(lineNumber: number, contentText: string, column = Constants.MAX_SAFE_SMALL_INTEGER): IDecorationOptions { // If decoratorText is too long, trim and add ellipses. This could happen for minified files with everything on a single line if (contentText.length > MAX_INLINE_DECORATOR_LENGTH) { contentText = contentText.substr(0, MAX_INLINE_DECORATOR_LENGTH) + '...'; @@ -57,8 +60,8 @@ function createInlineValueDecoration(lineNumber: number, contentText: string): I range: { startLineNumber: lineNumber, endLineNumber: lineNumber, - startColumn: Constants.MAX_SAFE_SMALL_INTEGER, - endColumn: Constants.MAX_SAFE_SMALL_INTEGER + startColumn: column, + endColumn: column }, renderOptions: { after: { @@ -572,20 +575,77 @@ export class DebugEditorContribution implements IDebugEditorContribution { this.removeInlineValuesScheduler.cancel(); - const scopes = await stackFrame.getMostSpecificScopes(stackFrame.range); - // Get all top level children in the scope chain - const decorationsPerScope = await Promise.all(scopes.map(async scope => { - const children = await scope.getChildren(); - let range = new Range(0, 0, stackFrame.range.startLineNumber, stackFrame.range.startColumn); - if (scope.range) { - range = range.setStartPosition(scope.range.startLineNumber, scope.range.startColumn); - } + let allDecorations: IDecorationOptions[]; - return createInlineValueDecorationsInsideRange(children, range, model, this.wordToLineNumbersMap); - })); + if (InlineValuesProviderRegistry.has(model)) { + const findVariable = async (key: string): Promise => { + const scopes = await stackFrame.getMostSpecificScopes(stackFrame.range); + for (let scope of scopes) { + const variables = await scope.getChildren(); + for (let v of variables) { + if (v.name === key) { + return v.value; + } + } + } + return undefined; + }; + + const ranges = this.editor.getVisibleRangesPlusViewportAboveBelow(); + + const ctx = { stoppedLocation: new Range(1, 1, stackFrame.range.startLineNumber, stackFrame.range.startColumn) }; + const token = new CancellationTokenSource().token; + + const providers = InlineValuesProviderRegistry.ordered(model).reverse(); + + allDecorations = []; + + const promises = flatten(providers.map(provider => ranges.map(range => Promise.resolve(provider.provideInlineValues(model, range, ctx, token)).then(async (result) => { + if (result) { + for (let iv of result) { + let text: string; + switch (iv.type) { + case 'text': + text = iv.text; + break; + case 'variable': + const value = await findVariable(iv.variableName); + text = `${iv.variableName} = ${value}`; + break; + case 'expression': + text = `eval(${iv.expression})`; + break; + } + if (text) { + allDecorations.push(createInlineValueDecoration(iv.range.startLineNumber, text, iv.range.startColumn)); + } + } + } + }, err => { + onUnexpectedExternalError(err); + })))); + + await Promise.all(promises); + + } else { // one-size-fits-all strategy + + const scopes = await stackFrame.getMostSpecificScopes(stackFrame.range); + // Get all top level variables in the scope chain + const decorationsPerScope = await Promise.all(scopes.map(async scope => { + const variables = await scope.getChildren(); + + let range = new Range(0, 0, stackFrame.range.startLineNumber, stackFrame.range.startColumn); + if (scope.range) { + range = range.setStartPosition(scope.range.startLineNumber, scope.range.startColumn); + } + + return createInlineValueDecorationsInsideRange(variables, range, model, this.wordToLineNumbersMap); + })); + + allDecorations = decorationsPerScope.reduce((previous, current) => previous.concat(current), []); + } - const allDecorations = decorationsPerScope.reduce((previous, current) => previous.concat(current), []); this.editor.setDecorations(INLINE_VALUE_DECORATION_KEY, allDecorations); } From 8aa800e459adc6f56610df90b1bcff30e03acb01 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 16 Feb 2021 16:15:47 +0100 Subject: [PATCH 205/325] allow to exclude a context key from registry, allow to provide type eplicitly, https://github.com/microsoft/vscode/issues/114867 --- src/vs/platform/contextkey/common/contextkey.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/contextkey/common/contextkey.ts b/src/vs/platform/contextkey/common/contextkey.ts index 22405c003f8..6ecb8a5dc76 100644 --- a/src/vs/platform/contextkey/common/contextkey.ts +++ b/src/vs/platform/contextkey/common/contextkey.ts @@ -1273,12 +1273,16 @@ export class RawContextKey extends ContextKeyDefinedExpr { private readonly _defaultValue: T | undefined; - constructor(readonly key: string, defaultValue: T | undefined, description?: string) { + constructor(readonly key: string, defaultValue: T | undefined, metaOrHide?: string | true | { type: string, description: string }) { super(key); this._defaultValue = defaultValue; // collect all context keys into a central place - RawContextKey._info.push({ key, description, type: typeof defaultValue }); + if (typeof metaOrHide === 'object') { + RawContextKey._info.push({ ...metaOrHide, key }); + } else if (metaOrHide !== true) { + RawContextKey._info.push({ key, description: metaOrHide, type: typeof defaultValue }); + } } public bindTo(target: IContextKeyService): IContextKey { From 6200437f3f111bb677f972f49aae29c2a1cd488b Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 16 Feb 2021 16:33:41 +0100 Subject: [PATCH 206/325] add description to some RawContextKey-instances --- src/vs/editor/browser/core/keybindingCancellation.ts | 2 +- src/vs/editor/contrib/message/messageController.ts | 2 +- .../callHierarchy/browser/callHierarchy.contribution.ts | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/browser/core/keybindingCancellation.ts b/src/vs/editor/browser/core/keybindingCancellation.ts index 1f260f9b6cd..03d3347862b 100644 --- a/src/vs/editor/browser/core/keybindingCancellation.ts +++ b/src/vs/editor/browser/core/keybindingCancellation.ts @@ -22,7 +22,7 @@ interface IEditorCancellationTokens { cancel(editor: ICodeEditor): void; } -const ctxCancellableOperation = new RawContextKey('cancellableOperation', false); +const ctxCancellableOperation = new RawContextKey('cancellableOperation', false, 'Whether the editor runs a cancellable operation, e.g. like \'Peek References\''); registerSingleton(IEditorCancellationTokens, class implements IEditorCancellationTokens { diff --git a/src/vs/editor/contrib/message/messageController.ts b/src/vs/editor/contrib/message/messageController.ts index 319f0d521d7..8f3a8dbbc2e 100644 --- a/src/vs/editor/contrib/message/messageController.ts +++ b/src/vs/editor/contrib/message/messageController.ts @@ -24,7 +24,7 @@ export class MessageController implements IEditorContribution { public static readonly ID = 'editor.contrib.messageController'; - static readonly MESSAGE_VISIBLE = new RawContextKey('messageVisible', false); + static readonly MESSAGE_VISIBLE = new RawContextKey('messageVisible', false, 'Whether the editor is currently showing an inline message'); static get(editor: ICodeEditor): MessageController { return editor.getContribution(MessageController.ID); diff --git a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts index 85c2711cb46..a3b90078e4e 100644 --- a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts +++ b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts @@ -26,9 +26,9 @@ import { MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { Codicon } from 'vs/base/common/codicons'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; -const _ctxHasCallHierarchyProvider = new RawContextKey('editorHasCallHierarchyProvider', false); -const _ctxCallHierarchyVisible = new RawContextKey('callHierarchyVisible', false); -const _ctxCallHierarchyDirection = new RawContextKey('callHierarchyDirection', undefined); +const _ctxHasCallHierarchyProvider = new RawContextKey('editorHasCallHierarchyProvider', false, 'Whether a call hierarchy provider is available'); +const _ctxCallHierarchyVisible = new RawContextKey('callHierarchyVisible', false, 'Whether call hierarchy peek is currently showing'); +const _ctxCallHierarchyDirection = new RawContextKey('callHierarchyDirection', undefined, { type: 'string', description: 'Whether call hierarchy shows incoming or outgoing calls' }); function sanitizedDirection(candidate: string): CallHierarchyDirection { return candidate === CallHierarchyDirection.CallsFrom || candidate === CallHierarchyDirection.CallsTo From a17ad41546ce886c99477e71a82cbdc65b31d69b Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 16 Feb 2021 16:41:40 +0100 Subject: [PATCH 207/325] use nls#localize for context key descriptions --- src/vs/editor/browser/core/keybindingCancellation.ts | 3 ++- src/vs/editor/contrib/message/messageController.ts | 2 +- .../callHierarchy/browser/callHierarchy.contribution.ts | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/browser/core/keybindingCancellation.ts b/src/vs/editor/browser/core/keybindingCancellation.ts index 03d3347862b..206fbeac885 100644 --- a/src/vs/editor/browser/core/keybindingCancellation.ts +++ b/src/vs/editor/browser/core/keybindingCancellation.ts @@ -12,6 +12,7 @@ import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cance import { LinkedList } from 'vs/base/common/linkedList'; import { createDecorator, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { localize } from 'vs/nls'; const IEditorCancellationTokens = createDecorator('IEditorCancelService'); @@ -22,7 +23,7 @@ interface IEditorCancellationTokens { cancel(editor: ICodeEditor): void; } -const ctxCancellableOperation = new RawContextKey('cancellableOperation', false, 'Whether the editor runs a cancellable operation, e.g. like \'Peek References\''); +const ctxCancellableOperation = new RawContextKey('cancellableOperation', false, localize('cancellableOperation', 'Whether the editor runs a cancellable operation, e.g. like \'Peek References\'')); registerSingleton(IEditorCancellationTokens, class implements IEditorCancellationTokens { diff --git a/src/vs/editor/contrib/message/messageController.ts b/src/vs/editor/contrib/message/messageController.ts index 8f3a8dbbc2e..d6f3357d3cd 100644 --- a/src/vs/editor/contrib/message/messageController.ts +++ b/src/vs/editor/contrib/message/messageController.ts @@ -24,7 +24,7 @@ export class MessageController implements IEditorContribution { public static readonly ID = 'editor.contrib.messageController'; - static readonly MESSAGE_VISIBLE = new RawContextKey('messageVisible', false, 'Whether the editor is currently showing an inline message'); + static readonly MESSAGE_VISIBLE = new RawContextKey('messageVisible', false, nls.localize('messageVisible', 'Whether the editor is currently showing an inline message')); static get(editor: ICodeEditor): MessageController { return editor.getContribution(MessageController.ID); diff --git a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts index a3b90078e4e..bcdb3736d19 100644 --- a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts +++ b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts @@ -26,9 +26,9 @@ import { MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { Codicon } from 'vs/base/common/codicons'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; -const _ctxHasCallHierarchyProvider = new RawContextKey('editorHasCallHierarchyProvider', false, 'Whether a call hierarchy provider is available'); -const _ctxCallHierarchyVisible = new RawContextKey('callHierarchyVisible', false, 'Whether call hierarchy peek is currently showing'); -const _ctxCallHierarchyDirection = new RawContextKey('callHierarchyDirection', undefined, { type: 'string', description: 'Whether call hierarchy shows incoming or outgoing calls' }); +const _ctxHasCallHierarchyProvider = new RawContextKey('editorHasCallHierarchyProvider', false, localize('editorHasCallHierarchyProvider', 'Whether a call hierarchy provider is available')); +const _ctxCallHierarchyVisible = new RawContextKey('callHierarchyVisible', false, localize('callHierarchyVisible', 'Whether call hierarchy peek is currently showing')); +const _ctxCallHierarchyDirection = new RawContextKey('callHierarchyDirection', undefined, { type: 'string', description: localize('callHierarchyDirection', 'Whether call hierarchy shows incoming or outgoing calls') }); function sanitizedDirection(candidate: string): CallHierarchyDirection { return candidate === CallHierarchyDirection.CallsFrom || candidate === CallHierarchyDirection.CallsTo From 7a9867c841e0222a08d29cbe6d0cc1512ba4c6e0 Mon Sep 17 00:00:00 2001 From: SteVen Batten <6561887+sbatten@users.noreply.github.com> Date: Tue, 16 Feb 2021 07:48:31 -0800 Subject: [PATCH 208/325] first draft editor (#116599) --- src/vs/base/common/network.ts | 2 + .../workspace/common/workspaceTrust.ts | 5 + .../preferences/browser/settingsEditor2.ts | 2 +- .../preferences/browser/settingsTree.ts | 2 +- .../browser/workspace.contribution.ts | 29 +- .../browser/workspaceTrustEditor.css | 73 +++ .../workspace/browser/workspaceTrustEditor.ts | 177 +++++++ .../workspace/browser/workspaceTrustTree.ts | 471 ++++++++++++++++++ .../browser/workspaceTrustEditorInput.ts | 42 ++ .../workspaces/common/workspaceTrust.ts | 50 ++ 10 files changed, 848 insertions(+), 5 deletions(-) create mode 100644 src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css create mode 100644 src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts create mode 100644 src/vs/workbench/contrib/workspace/browser/workspaceTrustTree.ts create mode 100644 src/vs/workbench/services/workspaces/browser/workspaceTrustEditorInput.ts diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts index a409e7722ab..402d5149722 100644 --- a/src/vs/base/common/network.ts +++ b/src/vs/base/common/network.ts @@ -64,6 +64,8 @@ export namespace Schemas { export const vscodeSettings = 'vscode-settings'; + export const vscodeWorkspaceTrust = 'vscode-workspace-trust'; + export const webviewPanel = 'webview-panel'; /** diff --git a/src/vs/platform/workspace/common/workspaceTrust.ts b/src/vs/platform/workspace/common/workspaceTrust.ts index 56f4fae82dc..629eddaf9a0 100644 --- a/src/vs/platform/workspace/common/workspaceTrust.ts +++ b/src/vs/platform/workspace/common/workspaceTrust.ts @@ -37,6 +37,11 @@ export interface IWorkspaceTrustModel { setFolderTrustState(folder: URI, trustState: WorkspaceTrustState): void; getFolderTrustState(folder: URI): WorkspaceTrustState; + + setTrustedFolders(folders: URI[]): void; + setUntrustedFolders(folders: URI[]): void; + + getTrustStateInfo(): IWorkspaceTrustStateInfo; } export interface IWorkspaceTrustRequest { diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts index 5f4734250dd..8d7405e04fe 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts @@ -61,7 +61,7 @@ export const enum SettingsFocusContext { SettingControl } -function createGroupIterator(group: SettingsTreeGroupElement): Iterable> { +export function createGroupIterator(group: SettingsTreeGroupElement): Iterable> { return Iterable.map(group.children, g => { return { element: g, diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts index 6cee6eb3ffe..298ac757dd9 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts @@ -1828,7 +1828,7 @@ class SettingsTreeDelegate extends CachedListVirtualDelegate extends ObjectTreeModel { +export class NonCollapsibleObjectTreeModel extends ObjectTreeModel { isCollapsible(element: T): boolean { return false; } diff --git a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts index 8d6cb051ee9..d88325ffb9c 100644 --- a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts +++ b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts @@ -3,11 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import 'vs/css!./workspaceTrustEditor'; +import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { localize } from 'vs/nls'; import { Action2, MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { Severity } from 'vs/platform/notification/common/notification'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkspaceTrustService, WorkspaceTrustState, WorkspaceTrustStateChangeEvent, workspaceTrustStateToString } from 'vs/platform/workspace/common/workspaceTrust'; @@ -24,7 +26,10 @@ import { ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from 'vs/workbench/services/statusbar/common/statusbar'; -import { WorkspaceTrustContext, WORKSPACE_TRUST_ENABLED, WORKSPACE_TRUST_URI } from 'vs/workbench/services/workspaces/common/workspaceTrust'; +import { IEditorRegistry, Extensions as EditorExtensions, EditorDescriptor } from 'vs/workbench/browser/editor'; +import { WorkspaceTrustEditor } from 'vs/workbench/contrib/workspace/browser/workspaceTrustEditor'; +import { WorkspaceTrustEditorInput } from 'vs/workbench/services/workspaces/browser/workspaceTrustEditorInput'; +import { WorkspaceTrustContext, WORKSPACE_TRUST_ENABLED } from 'vs/workbench/services/workspaces/common/workspaceTrust'; const workspaceTrustIcon = registerIcon('workspace-trust-icon', Codicon.shield, localize('workspaceTrustIcon', "Icon for workspace trust badge.")); @@ -181,6 +186,20 @@ Registry.as(WorkbenchExtensions.Workbench).regi LifecyclePhase.Ready ); +/** + * Trusted Workspace GUI Editor + */ +Registry.as(EditorExtensions.Editors).registerEditor( + EditorDescriptor.create( + WorkspaceTrustEditor, + WorkspaceTrustEditor.ID, + localize('workspaceTrustEditor', "Workspace Trust Editor") + ), + [ + new SyncDescriptor(WorkspaceTrustEditorInput) + ] +); + /* * Actions */ @@ -285,7 +304,11 @@ registerAction2(class extends Action2 { run(accessor: ServicesAccessor) { const editorService = accessor.get(IEditorService); - editorService.openEditor({ resource: WORKSPACE_TRUST_URI, mode: 'jsonc', options: { pinned: true } }); + const instantiationService = accessor.get(IInstantiationService); + + const input = instantiationService.createInstance(WorkspaceTrustEditorInput); + + editorService.openEditor(input); return; } }); diff --git a/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css new file mode 100644 index 00000000000..371217bd035 --- /dev/null +++ b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css @@ -0,0 +1,73 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +.monaco-icon-label.file-icon.workspacetrusteditor-name-file-icon.ext-file-icon.tab-label::before { + font-family: 'codicon'; + content: '\eb53'; +} + +.workspace-trust-editor.settings-editor { + max-width: 1000px; + padding-top: 11px; + padding-left: 15px; + padding-right: 15px; + margin: auto; +} + +.workspace-trust-editor.settings-editor > .workspace-trust-header { + border-bottom: solid 1px; +} + +.workspace-trust-editor.settings-editor .workspace-trust-header .workspace-trust-title { + font-size: 24px; + font-weight: 600; + padding: 10px 0px; +} + +/** Buttons Container */ +.workspace-trust-editor.settings-editor .workspace-trust-header .workspace-trust-buttons-row { + display: flex; + align-items: center; + justify-content: flex-end; + padding-right: 1px; + overflow: hidden; /* buttons row should never overflow */ +} + +.workspace-trust-editor.settings-editor .workspace-trust-header .workspace-trust-buttons-row { + display: flex; + white-space: nowrap; + padding: 20px 10px 10px; +} + +/** Buttons */ +.workspace-trust-editor.settings-editor .workspace-trust-header .workspace-trust-buttons-row .workspace-trust-buttons { + display: flex; + overflow: hidden; +} + +.workspace-trust-editor.settings-editor .workspace-trust-header .workspace-trust-buttons-row .workspace-trust-buttons .monaco-button { + width: fit-content; + width: -moz-fit-content; + padding: 5px 10px; + overflow: hidden; + text-overflow: ellipsis; + margin: 4px 5px; /* allows button focus outline to be visible */ + outline-offset: 2px !important; +} + +.monaco-workbench.vs .workspace-trust-editor.settings-editor > .workspace-trust-header { + border-color: #cccccc; +} + +.monaco-workbench.vs-dark .workspace-trust-editor.settings-editor > .workspace-trust-header{ + border-color: #3c3c3c; +} + + +/** Settings */ +.workspace-trust-editor.settings-editor > .settings-body .settings-tree-container .monaco-list-row .monaco-tl-contents { + padding-left: 0px; +} + diff --git a/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts new file mode 100644 index 00000000000..33bc5e1d73a --- /dev/null +++ b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts @@ -0,0 +1,177 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { $, append, clearNode, Dimension, EventHelper } from 'vs/base/browser/dom'; +import { ButtonBar } from 'vs/base/browser/ui/button/button'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { Iterable } from 'vs/base/common/iterator'; +import { isArray } from 'vs/base/common/types'; +import { URI } from 'vs/base/common/uri'; +import { localize } from 'vs/nls'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { WorkspaceTrustState } from 'vs/platform/workspace/common/workspaceTrust'; +import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; +import { EditorOptions, IEditorOpenContext } from 'vs/workbench/common/editor'; +import { IWorkspaceTrustSettingChangeEvent, WorkspaceTrustSettingArrayRenderer, WorkspaceTrustTree, WorkspaceTrustTreeModel } from 'vs/workbench/contrib/workspace/browser/workspaceTrustTree'; +import { WorkspaceTrustEditorInput } from 'vs/workbench/services/workspaces/browser/workspaceTrustEditorInput'; +import { WorkspaceTrustEditorModel } from 'vs/workbench/services/workspaces/common/workspaceTrust'; + +export class WorkspaceTrustEditor extends EditorPane { + static readonly ID: string = 'workbench.editor.workspaceTrust'; + private rootElement!: HTMLElement; + private headerContainer!: HTMLElement; + private headerTitle!: HTMLElement; + private headerDescription!: HTMLElement; + private headerButtons!: HTMLElement; + private configurationContainer!: HTMLElement; + private trustSettingsTree!: WorkspaceTrustTree; + private workspaceTrustSettingsTreeModel!: WorkspaceTrustTreeModel; + private workspaceTrustEditorModel!: WorkspaceTrustEditorModel; + + constructor( + @ITelemetryService telemetryService: ITelemetryService, + @IThemeService themeService: IThemeService, + @IStorageService storageService: IStorageService, + @ICommandService private readonly commandService: ICommandService, + @IInstantiationService private readonly instantiationService: IInstantiationService + ) { super(WorkspaceTrustEditor.ID, telemetryService, themeService, storageService); } + + protected createEditor(parent: HTMLElement): void { + this.rootElement = append(parent, $('.workspace-trust-editor.settings-editor', { tabindex: '-1' })); + + this.createHeaderElement(this.rootElement); + this.createConfigurationElement(this.rootElement); + } + + async setInput(input: WorkspaceTrustEditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { + + await super.setInput(input, options, context, token); + if (token.isCancellationRequested) { return; } + + const model = await input.resolve(); + if (token.isCancellationRequested || !(model instanceof WorkspaceTrustEditorModel)) { + return; + } + + this._register(model.dataModel.onDidChangeTrustState(() => { + this.render(model); + })); + + this.render(model); + + this.workspaceTrustEditorModel = model; + } + + private getHeaderTitleText(trustState: WorkspaceTrustState): string { + switch (trustState) { + case WorkspaceTrustState.Trusted: + return localize('trustedHeader', "This Workspace is Trusted"); + case WorkspaceTrustState.Untrusted: + return localize('untrustedHeader', "This Workspace is Not Trusted"); + case WorkspaceTrustState.Unknown: + return localize('unknownHeader', "This Workspace has Not Been Trusted"); + } + } + + private getHeaderDescriptionText(trustState: WorkspaceTrustState): string { + switch (trustState) { + case WorkspaceTrustState.Trusted: + return localize('trustedHeaderDescription', "All features requiring trust in this workspace are enabled. Below is the current list of features that will be disabled you grant trust to the workspace. Note that after trust is given, new features requiring trust will automatically inheret the current workspace trust status."); + case WorkspaceTrustState.Untrusted: + return localize('untrustedHeaderDescription', "This workspace has limited functionality as some features will not work until trust is given to the current workspace. Below is the current list of features that will be disabled you grant trust to the workspace. Note that after trust is given, new features requiring trust will automatically inherit the current workspace trust status."); + case WorkspaceTrustState.Unknown: + return localize('unknownHeaderDescription', "This workspace has limited functionality as some features will not work until trust is given to the current workspace. Below is the current list of features that will be disabled you grant trust to the workspace. Note that after trust is given, new features requiring trust will automatically inherit the current workspace trust status."); + } + } + + private render(model: WorkspaceTrustEditorModel): void { + this.headerTitle.innerText = this.getHeaderTitleText(model.currentWorkspaceTrustState); + this.headerDescription.innerText = this.getHeaderDescriptionText(model.currentWorkspaceTrustState); + + clearNode(this.headerButtons); + const buttonBar = this._register(new ButtonBar(this.headerButtons)); + + const createButton = (label: string, command: string) => { + const button = buttonBar.addButton({ title: true }); + button.label = label; + this._register(button.onDidClick(e => { + if (e) { + EventHelper.stop(e); + } + + this.commandService.executeCommand(command); + })); + }; + + if (model.currentWorkspaceTrustState !== WorkspaceTrustState.Trusted) { + createButton(localize('trustButton', "Trust"), 'workbench.trust.grant'); + } + + if (model.currentWorkspaceTrustState !== WorkspaceTrustState.Untrusted) { + createButton(localize('doNotTrustButton', "Don't Trust"), 'workbench.trust.deny'); + } + + createButton(localize('learnMore', "Learn More"), 'workbench.trust.learnMore'); + + this.workspaceTrustSettingsTreeModel.update(model.dataModel.getTrustStateInfo()); + + this.trustSettingsTree.setChildren(null, Iterable.map(this.workspaceTrustSettingsTreeModel.settings, s => { return { element: s }; })); + } + + private createHeaderElement(parent: HTMLElement): void { + this.headerContainer = append(parent, $('.workspace-trust-header')); + this.headerTitle = append(this.headerContainer, $('.workspace-trust-title')); + this.headerDescription = append(this.headerContainer, $('.workspace-trust-description')); + + const buttonsRow = append(this.headerContainer, $('.workspace-trust-buttons-row')); + this.headerButtons = append(buttonsRow, $('.workspace-trust-buttons')); + } + + private createConfigurationElement(parent: HTMLElement): void { + this.configurationContainer = append(parent, $('.workspace-trust-settings.settings-body')); + + const workspaceTrustTreeContainer = append(this.configurationContainer, $('.workspace-trust-settings-tree-container.settings-tree-container')); + const renderer = this.instantiationService.createInstance(WorkspaceTrustSettingArrayRenderer,); + + this.trustSettingsTree = this._register(this.instantiationService.createInstance(WorkspaceTrustTree, + workspaceTrustTreeContainer, + [renderer])); + + this.workspaceTrustSettingsTreeModel = this.instantiationService.createInstance(WorkspaceTrustTreeModel); + + this._register(renderer.onDidChangeSetting(e => this.onDidChangeSetting(e))); + } + + private onDidChangeSetting(change: IWorkspaceTrustSettingChangeEvent) { + if (this.workspaceTrustEditorModel) { + if (isArray(change.value)) { + console.log(change.key); + console.log(change.value); + if (change.key === 'trustedFolders') { + this.workspaceTrustEditorModel.dataModel.setTrustedFolders(change.value.map(item => URI.file(item))); + } + + if (change.key === 'untrustedFolders') { + this.workspaceTrustEditorModel.dataModel.setUntrustedFolders(change.value.map(item => URI.file(item))); + } + } + } + } + + layout(dimension: Dimension): void { + if (!this.isVisible()) { + return; + } + + const listHeight = dimension.height - this.configurationContainer.offsetTop; + this.configurationContainer.style.height = `${listHeight}`; + + this.trustSettingsTree.layout(listHeight, dimension.width); + } +} diff --git a/src/vs/workbench/contrib/workspace/browser/workspaceTrustTree.ts b/src/vs/workbench/contrib/workspace/browser/workspaceTrustTree.ts new file mode 100644 index 00000000000..1abfc3cb2d7 --- /dev/null +++ b/src/vs/workbench/contrib/workspace/browser/workspaceTrustTree.ts @@ -0,0 +1,471 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { addDisposableListener, append, EventType, $, createStyleSheet, trackFocus } from 'vs/base/browser/dom'; +import { DefaultStyleController, IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; +import { IList } from 'vs/base/browser/ui/tree/indexTreeModel'; +import { IObjectTreeOptions } from 'vs/base/browser/ui/tree/objectTree'; +import { ITreeModel, ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree'; +import { Color, RGBA } from 'vs/base/common/color'; +import { Emitter, Event } from 'vs/base/common/event'; +import { Disposable, DisposableStore, dispose } from 'vs/base/common/lifecycle'; +import { isArray } from 'vs/base/common/types'; +import { localize } from 'vs/nls'; +import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { IListService, WorkbenchObjectTree } from 'vs/platform/list/browser/listService'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { editorBackground, errorForeground, focusBorder, foreground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground } from 'vs/platform/theme/common/colorRegistry'; +import { IColorTheme, ICssStyleCollector, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { NonCollapsibleObjectTreeModel } from 'vs/workbench/contrib/preferences/browser/settingsTree'; +import { focusedRowBackground, focusedRowBorder, IListDataItem, ISettingListChangeEvent, ListSettingWidget, rowHoverBackground, settingsHeaderForeground } from 'vs/workbench/contrib/preferences/browser/settingsWidgets'; +import { attachStyler } from 'vs/platform/theme/common/styler'; +import { CachedListVirtualDelegate } from 'vs/base/browser/ui/list/list'; +import { IWorkspaceTrustStateInfo, WorkspaceTrustState } from 'vs/platform/workspace/common/workspaceTrust'; + + +export class WorkspaceTrustSettingsTreeEntry { + id: string; + displayLabel: string; + setting: { + key: string; + description: string; + }; + value: string[]; + + constructor(key: string, displayLabel: string, description: string, value: string[]) { + this.setting = { key, description }; + this.displayLabel = displayLabel; + this.value = value; + this.id = key; + } +} + +export interface IWorkspaceTrustSettingItemTemplate { + onChange?: (value: T) => void; + + toDispose: DisposableStore; + context?: WorkspaceTrustSettingsTreeEntry; + containerElement: HTMLElement; + labelElement: HTMLElement; + descriptionElement: HTMLElement; + controlElement: HTMLElement; + elementDisposables: DisposableStore; +} + +interface IWorkspaceTrustSettingListItemTemplate extends IWorkspaceTrustSettingItemTemplate { + listWidget: ListSettingWidget; + validationErrorMessageElement: HTMLElement; +} + +export interface IWorkspaceTrustSettingChangeEvent { + key: string; + value: any; // undefined => reset/unconfigure +} + + +export class WorkspaceTrustSettingArrayRenderer extends Disposable implements ITreeRenderer { + templateId = 'template.setting.array'; + + static readonly CONTROL_CLASS = 'setting-control-focus-target'; + static readonly CONTROL_SELECTOR = '.' + WorkspaceTrustSettingArrayRenderer.CONTROL_CLASS; + static readonly CONTENTS_CLASS = 'setting-item-contents'; + static readonly CONTENTS_SELECTOR = '.' + WorkspaceTrustSettingArrayRenderer.CONTENTS_CLASS; + static readonly ALL_ROWS_SELECTOR = '.monaco-list-row'; + + static readonly SETTING_KEY_ATTR = 'data-key'; + static readonly SETTING_ID_ATTR = 'data-id'; + static readonly ELEMENT_FOCUSABLE_ATTR = 'data-focusable'; + + protected readonly _onDidChangeSetting = this._register(new Emitter()); + readonly onDidChangeSetting: Event = this._onDidChangeSetting.event; + + private readonly _onDidFocusSetting = this._register(new Emitter()); + readonly onDidFocusSetting: Event = this._onDidFocusSetting.event; + + private readonly _onDidChangeIgnoredSettings = this._register(new Emitter()); + readonly onDidChangeIgnoredSettings: Event = this._onDidChangeIgnoredSettings.event; + + constructor( + @IThemeService protected readonly _themeService: IThemeService, + @IContextViewService protected readonly _contextViewService: IContextViewService, + @IOpenerService protected readonly _openerService: IOpenerService, + @IInstantiationService protected readonly _instantiationService: IInstantiationService, + @ICommandService protected readonly _commandService: ICommandService, + @IContextMenuService protected readonly _contextMenuService: IContextMenuService, + @IKeybindingService protected readonly _keybindingService: IKeybindingService, + @IConfigurationService protected readonly _configService: IConfigurationService, + ) { + super(); + } + + renderCommonTemplate(tree: any, _container: HTMLElement, typeClass: string): IWorkspaceTrustSettingItemTemplate { + _container.classList.add('setting-item'); + _container.classList.add('setting-item-' + typeClass); + + const container = append(_container, $(WorkspaceTrustSettingArrayRenderer.CONTENTS_SELECTOR)); + container.classList.add('settings-row-inner-container'); + const titleElement = append(container, $('.setting-item-title')); + const labelCategoryContainer = append(titleElement, $('.setting-item-cat-label-container')); + const labelElement = append(labelCategoryContainer, $('span.setting-item-label')); + const descriptionElement = append(container, $('.setting-item-description')); + const modifiedIndicatorElement = append(container, $('.setting-item-modified-indicator')); + modifiedIndicatorElement.title = localize('modified', "Modified"); + + const valueElement = append(container, $('.setting-item-value')); + const controlElement = append(valueElement, $('div.setting-item-control')); + const toDispose = new DisposableStore(); + + const template: IWorkspaceTrustSettingItemTemplate = { + toDispose, + elementDisposables: new DisposableStore(), + containerElement: container, + labelElement, + descriptionElement, + controlElement + }; + + // Prevent clicks from being handled by list + toDispose.add(addDisposableListener(controlElement, EventType.MOUSE_DOWN, e => e.stopPropagation())); + + toDispose.add(addDisposableListener(titleElement, EventType.MOUSE_ENTER, e => container.classList.add('mouseover'))); + toDispose.add(addDisposableListener(titleElement, EventType.MOUSE_LEAVE, e => container.classList.remove('mouseover'))); + + return template; + } + + addSettingElementFocusHandler(template: IWorkspaceTrustSettingItemTemplate): void { + const focusTracker = trackFocus(template.containerElement); + template.toDispose.add(focusTracker); + focusTracker.onDidBlur(() => { + if (template.containerElement.classList.contains('focused')) { + template.containerElement.classList.remove('focused'); + } + }); + + focusTracker.onDidFocus(() => { + template.containerElement.classList.add('focused'); + + if (template.context) { + this._onDidFocusSetting.fire(template.context); + } + }); + } + + renderTemplate(container: HTMLElement): IWorkspaceTrustSettingListItemTemplate { + const common = this.renderCommonTemplate(null, container, 'list'); + const descriptionElement = common.containerElement.querySelector('.setting-item-description')!; + const validationErrorMessageElement = $('.setting-item-validation-message'); + descriptionElement.after(validationErrorMessageElement); + + const listWidget = this._instantiationService.createInstance(ListSettingWidget, common.controlElement); + listWidget.domNode.classList.add(WorkspaceTrustSettingArrayRenderer.CONTROL_CLASS); + common.toDispose.add(listWidget); + + const template: IWorkspaceTrustSettingListItemTemplate = { + ...common, + listWidget, + validationErrorMessageElement + }; + + this.addSettingElementFocusHandler(template); + + common.toDispose.add( + listWidget.onDidChangeList(e => { + const newList = this.computeNewList(template, e); + if (newList !== null && template.onChange) { + template.onChange(newList); + } + }) + ); + + return template; + } + + private computeNewList(template: IWorkspaceTrustSettingListItemTemplate, e: ISettingListChangeEvent): string[] | undefined | null { + if (template.context) { + let newValue: string[] = []; + if (isArray(template.context.value)) { + newValue = [...template.context.value]; + } + + if (e.targetIndex !== undefined) { + // Delete value + if (!e.item?.value && e.originalItem.value && e.targetIndex > -1) { + newValue.splice(e.targetIndex, 1); + } + // Update value + else if (e.item?.value && e.originalItem.value) { + if (e.targetIndex > -1) { + newValue[e.targetIndex] = e.item.value; + } + // For some reason, we are updating and cannot find original value + // Just append the value in this case + else { + newValue.push(e.item.value); + } + } + // Add value + else if (e.item?.value && !e.originalItem.value && e.targetIndex >= newValue.length) { + newValue.push(e.item.value); + } + } + + return newValue; + } + + return undefined; + } + + renderElement(node: ITreeNode, index: number, template: IWorkspaceTrustSettingListItemTemplate): void { + const element = node.element; + template.context = element; + + template.containerElement.setAttribute(WorkspaceTrustSettingArrayRenderer.SETTING_KEY_ATTR, element.setting.key); + template.containerElement.setAttribute(WorkspaceTrustSettingArrayRenderer.SETTING_ID_ATTR, element.id); + + template.labelElement.textContent = element.displayLabel; + + template.descriptionElement.innerText = element.setting.description; + + const onChange = (value: any) => this._onDidChangeSetting.fire({ key: element.setting.key, value }); + this.renderValue(element, template, onChange); + } + + protected renderValue(dataElement: WorkspaceTrustSettingsTreeEntry, template: IWorkspaceTrustSettingListItemTemplate, onChange: (value: string[] | undefined) => void): void { + const value = getListDisplayValue(dataElement); + template.listWidget.setValue(value); + template.context = dataElement; + + template.onChange = (v) => { + onChange(v); + renderArrayValidations(dataElement, template, v, false); + }; + + renderArrayValidations(dataElement, template, value.map(v => v.value), true); + } + + disposeTemplate(template: IWorkspaceTrustSettingItemTemplate): void { + dispose(template.toDispose); + } + + disposeElement(_element: ITreeNode, _index: number, template: IWorkspaceTrustSettingItemTemplate, _height: number | undefined): void { + if (template.elementDisposables) { + template.elementDisposables.clear(); + } + } +} + +export class WorkspaceTrustTree extends WorkbenchObjectTree { + constructor( + container: HTMLElement, + renderers: ITreeRenderer[], + @IContextKeyService contextKeyService: IContextKeyService, + @IListService listService: IListService, + @IThemeService themeService: IThemeService, + @IConfigurationService configurationService: IConfigurationService, + @IKeybindingService keybindingService: IKeybindingService, + @IAccessibilityService accessibilityService: IAccessibilityService, + @IInstantiationService instantiationService: IInstantiationService, + ) { + super('WorkspaceTrustTree', container, + new WorkspaceTrustTreeDelegate(), + renderers, + { + horizontalScrolling: false, + supportDynamicHeights: true, + identityProvider: { + getId(e) { + return e.id; + } + }, + accessibilityProvider: new WorkspaceTrustTreeAccessibilityProvider(), + styleController: id => new DefaultStyleController(createStyleSheet(container), id), + smoothScrolling: configurationService.getValue('workbench.list.smoothScrolling'), + multipleSelectionSupport: false, + }, + contextKeyService, + listService, + themeService, + configurationService, + keybindingService, + accessibilityService, + ); + + this.disposables.add(registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => { + const foregroundColor = theme.getColor(foreground); + if (foregroundColor) { + // Links appear inside other elements in markdown. CSS opacity acts like a mask. So we have to dynamically compute the description color to avoid + // applying an opacity to the link color. + const fgWithOpacity = new Color(new RGBA(foregroundColor.rgba.r, foregroundColor.rgba.g, foregroundColor.rgba.b, 0.9)); + collector.addRule(`.workspace-trust-editor > .workspace-trust-settings > .workspace-trust-settings-tree-container .setting-item-contents .setting-item-description { color: ${fgWithOpacity}; }`); + collector.addRule(`.workspace-trust-editor > .workspace-trust-settings .settings-toc-container .monaco-list-row:not(.selected) { color: ${fgWithOpacity}; }`); + + // Hack for subpixel antialiasing + collector.addRule(`.workspace-trust-editor > .workspace-trust-settings > .workspace-trust-settings-tree-container .setting-item-contents .setting-item-title .setting-item-overrides, + .workspace-trust-editor > .workspace-trust-settings > .workspace-trust-settings-tree-container .setting-item-contents .setting-item-title .setting-item-ignored { color: ${fgWithOpacity}; }`); + } + + const errorColor = theme.getColor(errorForeground); + if (errorColor) { + collector.addRule(`.workspace-trust-editor > .workspace-trust-settings > .workspace-trust-settings-tree-container .setting-item-contents .setting-item-deprecation-message { color: ${errorColor}; }`); + } + + const invalidInputBackground = theme.getColor(inputValidationErrorBackground); + if (invalidInputBackground) { + collector.addRule(`.workspace-trust-editor > .workspace-trust-settings > .workspace-trust-settings-tree-container .setting-item-contents .setting-item-validation-message { background-color: ${invalidInputBackground}; }`); + } + + const invalidInputForeground = theme.getColor(inputValidationErrorForeground); + if (invalidInputForeground) { + collector.addRule(`.workspace-trust-editor > .workspace-trust-settings > .workspace-trust-settings-tree-container .setting-item-contents .setting-item-validation-message { color: ${invalidInputForeground}; }`); + } + + const invalidInputBorder = theme.getColor(inputValidationErrorBorder); + if (invalidInputBorder) { + collector.addRule(`.workspace-trust-editor > .workspace-trust-settings > .workspace-trust-settings-tree-container .setting-item-contents .setting-item-validation-message { border-style:solid; border-width: 1px; border-color: ${invalidInputBorder}; }`); + collector.addRule(`.workspace-trust-editor > .workspace-trust-settings > .workspace-trust-settings-tree-container .setting-item.invalid-input .setting-item-control .monaco-inputbox.idle { outline-width: 0; border-style:solid; border-width: 1px; border-color: ${invalidInputBorder}; }`); + } + + const focusedRowBackgroundColor = theme.getColor(focusedRowBackground); + if (focusedRowBackgroundColor) { + collector.addRule(`.workspace-trust-editor > .workspace-trust-settings > .workspace-trust-settings-tree-container .monaco-list-row.focused .settings-row-inner-container { background-color: ${focusedRowBackgroundColor}; }`); + } + + const rowHoverBackgroundColor = theme.getColor(rowHoverBackground); + if (rowHoverBackgroundColor) { + collector.addRule(`.workspace-trust-editor > .workspace-trust-settings > .workspace-trust-settings-tree-container .monaco-list-row:not(.focused) .settings-row-inner-container:hover { background-color: ${rowHoverBackgroundColor}; }`); + } + + const focusedRowBorderColor = theme.getColor(focusedRowBorder); + if (focusedRowBorderColor) { + collector.addRule(`.workspace-trust-editor > .workspace-trust-settings > .workspace-trust-settings-tree-container .monaco-list:focus-within .monaco-list-row.focused .setting-item-contents::before, + .workspace-trust-editor > .workspace-trust-settings > .workspace-trust-settings-tree-container .monaco-list:focus-within .monaco-list-row.focused .setting-item-contents::after { border-top: 1px solid ${focusedRowBorderColor} }`); + collector.addRule(`.workspace-trust-editor > .workspace-trust-settings > .workspace-trust-settings-tree-container .monaco-list:focus-within .monaco-list-row.focused .settings-group-title-label::before, + .workspace-trust-editor > .workspace-trust-settings > .workspace-trust-settings-tree-container .monaco-list:focus-within .monaco-list-row.focused .settings-group-title-label::after { border-top: 1px solid ${focusedRowBorderColor} }`); + } + + const headerForegroundColor = theme.getColor(settingsHeaderForeground); + if (headerForegroundColor) { + collector.addRule(`.workspace-trust-editor > .workspace-trust-settings > .workspace-trust-settings-tree-container .settings-group-title-label { color: ${headerForegroundColor}; }`); + collector.addRule(`.workspace-trust-editor > .workspace-trust-settings > .workspace-trust-settings-tree-container .setting-item-label { color: ${headerForegroundColor}; }`); + } + + const focusBorderColor = theme.getColor(focusBorder); + if (focusBorderColor) { + collector.addRule(`.workspace-trust-editor > .workspace-trust-settings > .workspace-trust-settings-tree-container .setting-item-contents .setting-item-markdown a:focus { outline-color: ${focusBorderColor} }`); + } + })); + + this.getHTMLElement().classList.add('settings-editor-tree'); + + this.disposables.add(attachStyler(themeService, { + listBackground: editorBackground, + listActiveSelectionBackground: editorBackground, + listActiveSelectionForeground: foreground, + listFocusAndSelectionBackground: editorBackground, + listFocusAndSelectionForeground: foreground, + listFocusBackground: editorBackground, + listFocusForeground: foreground, + listHoverForeground: foreground, + listHoverBackground: editorBackground, + listHoverOutline: editorBackground, + listFocusOutline: editorBackground, + listInactiveSelectionBackground: editorBackground, + listInactiveSelectionForeground: foreground, + listInactiveFocusBackground: editorBackground, + listInactiveFocusOutline: editorBackground + }, colors => { + this.style(colors); + })); + + this.disposables.add(configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('workbench.list.smoothScrolling')) { + this.updateOptions({ + smoothScrolling: configurationService.getValue('workbench.list.smoothScrolling') + }); + } + })); + } + + protected createModel(user: string, view: IList>, options: IObjectTreeOptions): ITreeModel { + return new NonCollapsibleObjectTreeModel(user, view, options); + } +} + +export class WorkspaceTrustTreeModel { + + settings: WorkspaceTrustSettingsTreeEntry[] = []; + + update(trustInfo: IWorkspaceTrustStateInfo): void { + this.settings = []; + if (trustInfo.localFolders) { + const trustedFolders = trustInfo.localFolders.filter(folder => folder.trustState === WorkspaceTrustState.Trusted).map(folder => folder.uri); + const untrustedFolders = trustInfo.localFolders.filter(folder => folder.trustState === WorkspaceTrustState.Untrusted).map(folder => folder.uri); + + this.settings.push(new WorkspaceTrustSettingsTreeEntry( + 'trustedFolders', + localize('trustedFolders', "Trusted Folders"), + localize('trustedFoldersDescription', "All workspaces under the following folders will be trusted. In the event of a conflict with untrusted folders, the nearest parent will determine trust."), + trustedFolders)); + + this.settings.push(new WorkspaceTrustSettingsTreeEntry( + 'untrustedFolders', + localize('untrustedFolders', "Untrusted Folders"), + localize('untrustedFoldersDescription', "All workspaces under the following folders will not be trusted. In the event of a conflict with trusted folders, the nearest parent will determine trust."), + untrustedFolders)); + } + } +} + +class WorkspaceTrustTreeAccessibilityProvider implements IListAccessibilityProvider { + getAriaLabel(element: WorkspaceTrustSettingsTreeEntry) { + if (element instanceof WorkspaceTrustSettingsTreeEntry) { + return `element.displayLabel`; + } + + return null; + } + + getWidgetAriaLabel() { + return localize('settings', "Workspace Trust Setting"); + } +} + +class WorkspaceTrustTreeDelegate extends CachedListVirtualDelegate { + + getTemplateId(element: WorkspaceTrustSettingsTreeEntry): string { + return 'template.setting.array'; + } + + hasDynamicHeight(element: WorkspaceTrustSettingsTreeEntry): boolean { + return true; + } + + protected estimateHeight(element: WorkspaceTrustSettingsTreeEntry): number { + return 104; + } +} + +function getListDisplayValue(element: WorkspaceTrustSettingsTreeEntry): IListDataItem[] { + if (!element.value || !isArray(element.value)) { + return []; + } + + return element.value.map((key: string) => { + return { + value: key + }; + }); +} + +function renderArrayValidations(dataElement: WorkspaceTrustSettingsTreeEntry, template: IWorkspaceTrustSettingListItemTemplate, v: string[] | undefined, arg3: boolean) { +} + diff --git a/src/vs/workbench/services/workspaces/browser/workspaceTrustEditorInput.ts b/src/vs/workbench/services/workspaces/browser/workspaceTrustEditorInput.ts new file mode 100644 index 00000000000..78181c577ee --- /dev/null +++ b/src/vs/workbench/services/workspaces/browser/workspaceTrustEditorInput.ts @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Schemas } from 'vs/base/common/network'; +import { URI } from 'vs/base/common/uri'; +import { localize } from 'vs/nls'; +import { IWorkspaceTrustService } from 'vs/platform/workspace/common/workspaceTrust'; +import { EditorInput } from 'vs/workbench/common/editor'; +import { WorkspaceTrustEditorModel, WorkspaceTrustService } from 'vs/workbench/services/workspaces/common/workspaceTrust'; + +export class WorkspaceTrustEditorInput extends EditorInput { + static readonly ID: string = 'workbench.input.workspaceTrust'; + + readonly resource: URI = URI.from({ + scheme: Schemas.vscodeWorkspaceTrust, + path: `workspaceTrustEditor` + }); + + constructor( + @IWorkspaceTrustService private readonly workspaceTrustService: WorkspaceTrustService + ) { + super(); + } + + getTypeId(): string { + return WorkspaceTrustEditorInput.ID; + } + + matches(otherInput: unknown): boolean { + return otherInput instanceof WorkspaceTrustEditorInput; + } + + getName(): string { + return localize('workspaceTrustEditorInputName', "Workspace Trust"); + } + + async resolve(): Promise { + return this.workspaceTrustService.workspaceTrustEditorModel; + } +} diff --git a/src/vs/workbench/services/workspaces/common/workspaceTrust.ts b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts index f8ea335eae8..192c25c7aed 100644 --- a/src/vs/workbench/services/workspaces/common/workspaceTrust.ts +++ b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts @@ -13,6 +13,7 @@ import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storag import { IWorkspace, IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceTrustModel, IWorkspaceTrustRequest, IWorkspaceTrustRequestModel, IWorkspaceTrustService, IWorkspaceTrustStateInfo, WorkspaceTrustState, WorkspaceTrustStateChangeEvent } from 'vs/platform/workspace/common/workspaceTrust'; import { isEqual, isEqualOrParent } from 'vs/base/common/extpath'; +import { EditorModel } from 'vs/workbench/common/editor'; export const WORKSPACE_TRUST_ENABLED = 'workspace.trustEnabled'; export const WORKSPACE_TRUST_STORAGE_KEY = 'content.trust.model.key'; @@ -23,6 +24,18 @@ export const WorkspaceTrustContext = { TrustState: new RawContextKey('workspaceTrustState', WorkspaceTrustState.Unknown) }; +export class WorkspaceTrustEditorModel extends EditorModel { + constructor( + readonly dataModel: IWorkspaceTrustModel, + private readonly workspaceTrustService: WorkspaceTrustService + ) { + super(); + } + + get currentWorkspaceTrustState(): WorkspaceTrustState { + return this.workspaceTrustService.getWorkspaceTrustState(); + } +} export class WorkspaceTrustModel extends Disposable implements IWorkspaceTrustModel { private storageKey = WORKSPACE_TRUST_STORAGE_KEY; @@ -82,6 +95,30 @@ export class WorkspaceTrustModel extends Disposable implements IWorkspaceTrustMo this._onDidChangeTrustState.fire(); } + setTrustedFolders(folders: URI[]): void { + this.trustStateInfo.localFolders = this.trustStateInfo.localFolders.filter(folder => folder.trustState !== WorkspaceTrustState.Trusted); + for (const folder of folders) { + this.trustStateInfo.localFolders.push({ + trustState: WorkspaceTrustState.Trusted, + uri: folder.fsPath + }); + } + + this.saveTrustInfo(); + } + + setUntrustedFolders(folders: URI[]): void { + this.trustStateInfo.localFolders = this.trustStateInfo.localFolders.filter(folder => folder.trustState !== WorkspaceTrustState.Untrusted); + for (const folder of folders) { + this.trustStateInfo.localFolders.push({ + trustState: WorkspaceTrustState.Untrusted, + uri: folder.fsPath + }); + } + + this.saveTrustInfo(); + } + setFolderTrustState(folder: URI, trustState: WorkspaceTrustState): void { let changed = false; @@ -135,6 +172,10 @@ export class WorkspaceTrustModel extends Disposable implements IWorkspaceTrustMo return result; } + + getTrustStateInfo(): IWorkspaceTrustStateInfo { + return this.trustStateInfo; + } } export class WorkspaceTrustRequestModel extends Disposable implements IWorkspaceTrustRequestModel { @@ -166,6 +207,7 @@ export class WorkspaceTrustService extends Disposable implements IWorkspaceTrust _serviceBrand: undefined; private readonly dataModel: IWorkspaceTrustModel; readonly requestModel: IWorkspaceTrustRequestModel; + private editorModel?: WorkspaceTrustEditorModel; private readonly _onDidChangeTrustState = this._register(new Emitter()); readonly onDidChangeTrustState = this._onDidChangeTrustState.event; @@ -212,6 +254,14 @@ export class WorkspaceTrustService extends Disposable implements IWorkspaceTrust this._onDidChangeTrustState.fire({ previousTrustState: previousState, currentTrustState: this._currentTrustState }); } + get workspaceTrustEditorModel(): WorkspaceTrustEditorModel { + if (this.editorModel === undefined) { + this.editorModel = this._register(new WorkspaceTrustEditorModel(this.dataModel, this)); + } + + return this.editorModel; + } + private calculateWorkspaceTrustState(): WorkspaceTrustState { if (!this.isWorkspaceTrustEnabled()) { return WorkspaceTrustState.Trusted; From 35abaaf6063cba33874402490974ccac42d535ba Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 16 Feb 2021 08:08:09 -0800 Subject: [PATCH 209/325] Log all lines in failing test --- .../src/singlefolder-tests/terminal.test.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index 5565059085c..9d84e92250a 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -55,39 +55,54 @@ import { assertNoRpc } from '../utils'; }); }); - test.skip('echo works in the default shell', async () => { + test('echo works in the default shell', async () => { + console.log(' test 1'); const terminal = await new Promise(r => { + console.log(' test 2'); disposables.push(window.onDidOpenTerminal(t => { + console.log(' test 3'); strictEqual(terminal, t); r(terminal); })); + console.log(' test 4'); // Use a single character to avoid winpty/conpty issues with injected sequences const terminal = window.createTerminal({ env: { TEST: '`' } }); + console.log(' test 5'); terminal.show(); }); + console.log(' test 6'); let data = ''; await new Promise(r => { + console.log(' test 7'); disposables.push(window.onDidWriteTerminalData(e => { + console.log(' test 8'); strictEqual(terminal, e.terminal); data += e.data; if (data.indexOf('`') !== 0) { + console.log(' test 9'); r(); } })); // Print an environment variable value so the echo statement doesn't get matched if (process.platform === 'win32') { + console.log(' test 10'); terminal.sendText(`$env:TEST`); } else { + console.log(' test 11'); terminal.sendText(`echo $TEST`); } }); + console.log(' test 12'); await new Promise(r => { + console.log(' test 1'); terminal.dispose(); + console.log(' test 14'); disposables.push(window.onDidCloseTerminal(t => { + console.log(' test 15'); strictEqual(terminal, t); r(); })); From c441c567a31da4f6ddf4e9c7f0d14c1ad9395cf2 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 16 Feb 2021 17:10:12 +0100 Subject: [PATCH 210/325] storage - implement first cut migration support --- .../electron-sandbox/storageService2.ts | 83 +++++++++++++------ 1 file changed, 56 insertions(+), 27 deletions(-) diff --git a/src/vs/platform/storage/electron-sandbox/storageService2.ts b/src/vs/platform/storage/electron-sandbox/storageService2.ts index c9bbecee81c..5f8efb05026 100644 --- a/src/vs/platform/storage/electron-sandbox/storageService2.ts +++ b/src/vs/platform/storage/electron-sandbox/storageService2.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, MutableDisposable } from 'vs/base/common/lifecycle'; import { StorageScope, WillSaveStateReason, AbstractStorageService } from 'vs/platform/storage/common/storage'; import { Storage, IStorage } from 'vs/base/parts/storage/common/storage'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -16,8 +16,14 @@ import { joinPath } from 'vs/base/common/resources'; export class NativeStorageService2 extends AbstractStorageService { + // Global Storage is readonly and shared across windows private readonly globalStorage: IStorage; - private readonly workspaceStorage: IStorage | undefined; + + // Workspace Storage is scoped to a window but can change + // in the current window, when entering a workspace! + private workspaceStorage: IStorage | undefined = undefined; + private workspaceStorageId: string | undefined = undefined; + private workspaceStorageDisposables = this._register(new MutableDisposable()); private initializePromise: Promise | undefined; @@ -25,23 +31,44 @@ export class NativeStorageService2 extends AbstractStorageService { private runWhenIdleDisposable: IDisposable | undefined = undefined; constructor( - private workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined, - mainProcessService: IMainProcessService, + workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined, + private readonly mainProcessService: IMainProcessService, private readonly environmentService: IEnvironmentService ) { super(); - // Connect to storage via channel client - const storageDataBaseClient = new StorageDatabaseChannelClient(mainProcessService.getChannel('storage'), workspace); - this.globalStorage = new Storage(storageDataBaseClient.globalStorage); - this.workspaceStorage = storageDataBaseClient.workspaceStorage ? new Storage(storageDataBaseClient.workspaceStorage) : undefined; - - this.registerListeners(); + this.globalStorage = this.createGlobalStorage(); + this.workspaceStorage = this.createWorkspaceStorage(workspace); } - private registerListeners(): void { - this._register(this.globalStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.GLOBAL, key))); - this._register(this.workspaceStorage?.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.WORKSPACE, key)) ?? Disposable.None); + private createGlobalStorage(): IStorage { + const storageDataBaseClient = new StorageDatabaseChannelClient(this.mainProcessService.getChannel('storage'), undefined); + + const globalStorage = new Storage(storageDataBaseClient.globalStorage); + + this._register(globalStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.GLOBAL, key))); + + return globalStorage; + } + + private createWorkspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier): IStorage; + private createWorkspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined): IStorage | undefined; + private createWorkspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined): IStorage | undefined { + + // Keep id around for logging + this.workspaceStorageId = workspace?.id; + + // Create new + const storageDataBaseClient = new StorageDatabaseChannelClient(this.mainProcessService.getChannel('storage'), workspace); + if (storageDataBaseClient.workspaceStorage) { + const workspaceStorage = new Storage(storageDataBaseClient.workspaceStorage); + + this.workspaceStorageDisposables.value = workspaceStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.WORKSPACE, key)); + + return workspaceStorage; + } + + return undefined; } initialize(): Promise { @@ -76,7 +103,7 @@ export class NativeStorageService2 extends AbstractStorageService { } protected getLogDetails(scope: StorageScope): string | undefined { - return scope === StorageScope.GLOBAL ? this.environmentService.globalStorageHome.fsPath : this.workspace ? `${joinPath(this.environmentService.workspaceStorageHome, this.workspace.id, 'state.vscdb').fsPath} [!!! Experimental Main Storage !!!]` : undefined; + return scope === StorageScope.GLOBAL ? this.environmentService.globalStorageHome.fsPath : this.workspaceStorageId ? `${joinPath(this.environmentService.workspaceStorageHome, this.workspaceStorageId, 'state.vscdb').fsPath} [!!! Experimental Main Storage !!!]` : undefined; } private doFlushWhenIdle(): void { @@ -113,22 +140,24 @@ export class NativeStorageService2 extends AbstractStorageService { } async migrate(toWorkspace: IWorkspaceInitializationPayload): Promise { - // if (this.workspaceStoragePath === SQLiteStorageDatabase.IN_MEMORY_PATH) { - // return; // no migration needed if running in memory - // } - // // Close workspace DB to be able to copy - // await this.getStorage(StorageScope.WORKSPACE).close(); + // Keep current workspace storage items around to restore + const oldWorkspaceStorage = this.workspaceStorage; + const oldItems = oldWorkspaceStorage?.items ?? new Map(); - // // Prepare new workspace storage folder - // const result = await this.prepareWorkspaceStorageFolder(toWorkspace); + // Close current which will change to new workspace storage + if (oldWorkspaceStorage) { + await oldWorkspaceStorage.close(); + oldWorkspaceStorage.dispose(); + } - // const newWorkspaceStoragePath = join(result.path, NativeStorageService.WORKSPACE_STORAGE_NAME); + // Create new workspace storage & init + this.workspaceStorage = this.createWorkspaceStorage(toWorkspace); + await this.workspaceStorage.init(); - // // Copy current storage over to new workspace storage - // await copy(assertIsDefined(this.workspaceStoragePath), newWorkspaceStoragePath, { preserveSymlinks: false }); - - // // Recreate and init workspace storage - // return this.createWorkspaceStorage(newWorkspaceStoragePath).init(); + // Copy over previous keys + for (const [key, value] of oldItems) { + this.workspaceStorage.set(key, value); + } } } From 994ad37588262f8031d1127ae7d0e7424941aa71 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 16 Feb 2021 08:36:03 -0800 Subject: [PATCH 211/325] Log more in test --- .../vscode-api-tests/src/singlefolder-tests/terminal.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index 9d84e92250a..ec01fb7c560 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -78,9 +78,11 @@ import { assertNoRpc } from '../utils'; await new Promise(r => { console.log(' test 7'); disposables.push(window.onDidWriteTerminalData(e => { - console.log(' test 8'); + console.log(' test 8.1'); strictEqual(terminal, e.terminal); + console.log(' test 8.2'); data += e.data; + console.log(' test 8.3, data=' + data); if (data.indexOf('`') !== 0) { console.log(' test 9'); r(); From 7ce6ee7559094a83be0a5e081d54e70acac8fb9c Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 16 Feb 2021 08:03:07 -0800 Subject: [PATCH 212/325] testing: fix event listener leak Fixes #116775 --- .../testing/browser/testingDecorations.ts | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts index 567258a3597..415b2ae90ad 100644 --- a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts +++ b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts @@ -33,6 +33,7 @@ import { IMainThreadTestCollection, ITestService } from 'vs/workbench/contrib/te export class TestingDecorations extends Disposable implements IEditorContribution { private collection = this._register(new MutableDisposable>()); + private currentUri?: URI; private lastDecorations: ITestDecoration[] = []; constructor( @@ -52,9 +53,22 @@ export class TestingDecorations extends Disposable implements IEditorContributio } } })); + + this._register(this.results.onTestChanged(({ item: result }) => { + if (this.currentUri && result.item.location?.uri.toString() === this.currentUri.toString()) { + this.setDecorations(this.currentUri); + } + })); + this._register(this.results.onResultsChanged(() => { + if (this.currentUri) { + this.setDecorations(this.currentUri); + } + })); } private attachModel(uri?: URI) { + this.currentUri = uri; + if (!uri) { this.collection.value = undefined; this.clearDecorations(); @@ -62,15 +76,6 @@ export class TestingDecorations extends Disposable implements IEditorContributio } this.collection.value = this.testService.subscribeToDiffs(ExtHostTestingResource.TextDocument, uri, () => this.setDecorations(uri)); - this._register(this.results.onTestChanged(({ item: result }) => { - if (result.item.location?.uri.toString() === uri.toString()) { - this.setDecorations(uri); - } - })); - this._register(this.results.onResultsChanged(() => { - this.setDecorations(uri); - })); - this.setDecorations(uri); } From 68b67a345596557390e7618dd931af736a198ec9 Mon Sep 17 00:00:00 2001 From: Utku Gultopu Date: Tue, 16 Feb 2021 11:48:03 -0500 Subject: [PATCH 213/325] Keep misspelled property name in timerService Per https://github.com/microsoft/vscode/pull/116728#pullrequestreview-590976270. --- .../contrib/performance/browser/perfviewEditor.ts | 2 +- src/vs/workbench/services/timer/browser/timerService.ts | 8 ++++---- .../services/timer/electron-sandbox/timerService.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts b/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts index 7e65342f581..4b810831bab 100644 --- a/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts +++ b/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts @@ -156,7 +156,7 @@ class PerfModelContentProvider implements ITextModelContentProvider { if (metrics.meminfo) { md.li(`Memory(Process): ${(metrics.meminfo.workingSetSize / ByteSize.KB).toFixed(2)} MB working set(${(metrics.meminfo.privateBytes / ByteSize.KB).toFixed(2)}MB private, ${(metrics.meminfo.sharedBytes / ByteSize.KB).toFixed(2)}MB shared)`); } - md.li(`VM(likelihood): ${metrics.isVMLikelihood}%`); + md.li(`VM(likelihood): ${metrics.isVMLikelyhood}%`); md.li(`Initial Startup: ${metrics.initialStartup}`); md.li(`Has ${metrics.windowCount - 1} other windows`); md.li(`Screen Reader Active: ${metrics.hasAccessibilitySupport}`); diff --git a/src/vs/workbench/services/timer/browser/timerService.ts b/src/vs/workbench/services/timer/browser/timerService.ts index fbf80f6aad0..324de644b65 100644 --- a/src/vs/workbench/services/timer/browser/timerService.ts +++ b/src/vs/workbench/services/timer/browser/timerService.ts @@ -68,7 +68,7 @@ export interface IMemoryInfo { "cpus.model" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, "initialStartup" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "hasAccessibilitySupport" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "isVMLikelihood" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, + "isVMLikelyhood" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "emptyWorkbench" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "loadavg" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } } @@ -324,7 +324,7 @@ export interface IStartupMetrics { }; readonly hasAccessibilitySupport: boolean; - readonly isVMLikelihood?: number; + readonly isVMLikelyhood?: number; readonly platform?: string; readonly release?: string; readonly arch?: string; @@ -546,7 +546,7 @@ export abstract class AbstractTimerService implements ITimerService { meminfo: undefined, cpus: undefined, loadavg: undefined, - isVMLikelihood: undefined, + isVMLikelyhood: undefined, initialStartup, hasAccessibilitySupport: this._accessibilityService.isScreenReaderOptimized(), emptyWorkbench: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY @@ -578,7 +578,7 @@ export class TimerService extends AbstractTimerService { return 1; } protected async _extendStartupInfo(info: Writeable): Promise { - info.isVMLikelihood = 0; + info.isVMLikelyhood = 0; info.platform = navigator.userAgent; info.release = navigator.appVersion; } diff --git a/src/vs/workbench/services/timer/electron-sandbox/timerService.ts b/src/vs/workbench/services/timer/electron-sandbox/timerService.ts index feb1c404ae2..cfd5a044410 100644 --- a/src/vs/workbench/services/timer/electron-sandbox/timerService.ts +++ b/src/vs/workbench/services/timer/electron-sandbox/timerService.ts @@ -68,7 +68,7 @@ export class TimerService extends AbstractTimerService { sharedBytes: processMemoryInfo.shared }; - info.isVMLikelihood = Math.round((virtualMachineHint * 100)); + info.isVMLikelyhood = Math.round((virtualMachineHint * 100)); const rawCpus = osProperties.cpus; if (rawCpus && rawCpus.length > 0) { From d22941af5d75800591770e69fd6ef08593cf1d75 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 16 Feb 2021 18:14:55 +0100 Subject: [PATCH 214/325] startDebugActionViewItem: fix focus navigation within ActionBar --- .../debug/browser/debugActionViewItems.ts | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts b/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts index b600fc9943f..c6021398d25 100644 --- a/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts +++ b/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import { IAction, IActionRunner, IActionViewItem } from 'vs/base/common/actions'; +import { IAction } from 'vs/base/common/actions'; import { KeyCode } from 'vs/base/common/keyCodes'; import * as dom from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; @@ -19,20 +19,19 @@ import { IContextViewService } from 'vs/platform/contextview/browser/contextView import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ADD_CONFIGURATION_ID } from 'vs/workbench/contrib/debug/browser/debugCommands'; -import { SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; +import { BaseActionViewItem, SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; import { debugStart } from 'vs/workbench/contrib/debug/browser/debugIcons'; const $ = dom.$; -export class StartDebugActionViewItem implements IActionViewItem { +export class StartDebugActionViewItem extends BaseActionViewItem { private static readonly SEPARATOR = '─────────'; - actionRunner!: IActionRunner; private container!: HTMLElement; private start!: HTMLElement; private selectBox: SelectBox; - private options: { label: string, handler: (() => Promise) }[] = []; + private debugOptions: { label: string, handler: (() => Promise) }[] = []; private toDispose: IDisposable[]; private selected = 0; private providers: { label: string, type: string, pick: () => Promise<{ launch: ILaunch, config: IConfig } | undefined> }[] = []; @@ -47,6 +46,7 @@ export class StartDebugActionViewItem implements IActionViewItem { @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @IContextViewService contextViewService: IContextViewService, ) { + super(context, action); this.toDispose = []; this.selectBox = new SelectBox([], -1, contextViewService, undefined, { ariaLabel: nls.localize('debugLaunchConfigurations', 'Debug Launch Configurations') }); this.toDispose.push(this.selectBox); @@ -72,7 +72,6 @@ export class StartDebugActionViewItem implements IActionViewItem { this.start = dom.append(container, $(ThemeIcon.asCSSSelector(debugStart))); this.start.title = this.action.label; this.start.setAttribute('role', 'button'); - this.start.tabIndex = 0; this.toDispose.push(dom.addDisposableListener(this.start, dom.EventType.CLICK, () => { this.start.blur(); @@ -104,7 +103,7 @@ export class StartDebugActionViewItem implements IActionViewItem { } })); this.toDispose.push(this.selectBox.onDidSelect(async e => { - const target = this.options[e.index]; + const target = this.debugOptions[e.index]; const shouldBeSelected = target.handler ? await target.handler() : false; if (shouldBeSelected) { this.selected = e.index; @@ -151,11 +150,13 @@ export class StartDebugActionViewItem implements IActionViewItem { if (fromRight) { this.selectBox.focus(); } else { + this.start.tabIndex = 0; this.start.focus(); } } blur(): void { + this.start.tabIndex = -1; this.container.blur(); } @@ -165,7 +166,7 @@ export class StartDebugActionViewItem implements IActionViewItem { private updateOptions(): void { this.selected = 0; - this.options = []; + this.debugOptions = []; const manager = this.debugService.getConfigurationManager(); const inWorkspace = this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE; let lastGroup: string | undefined; @@ -173,17 +174,17 @@ export class StartDebugActionViewItem implements IActionViewItem { manager.getAllConfigurations().forEach(({ launch, name, presentation }) => { if (lastGroup !== presentation?.group) { lastGroup = presentation?.group; - if (this.options.length) { - this.options.push({ label: StartDebugActionViewItem.SEPARATOR, handler: () => Promise.resolve(false) }); - disabledIdxs.push(this.options.length - 1); + if (this.debugOptions.length) { + this.debugOptions.push({ label: StartDebugActionViewItem.SEPARATOR, handler: () => Promise.resolve(false) }); + disabledIdxs.push(this.debugOptions.length - 1); } } if (name === manager.selectedConfiguration.name && launch === manager.selectedConfiguration.launch) { - this.selected = this.options.length; + this.selected = this.debugOptions.length; } const label = inWorkspace ? `${name} (${launch.name})` : name; - this.options.push({ + this.debugOptions.push({ label, handler: async () => { await manager.selectConfiguration(launch, name); return true; @@ -194,9 +195,9 @@ export class StartDebugActionViewItem implements IActionViewItem { // Only take 3 elements from the recent dynamic configurations to not clutter the dropdown manager.getRecentDynamicConfigurations().slice(0, 3).forEach(({ name, type }) => { if (type === manager.selectedConfiguration.type && manager.selectedConfiguration.name === name) { - this.selected = this.options.length; + this.selected = this.debugOptions.length; } - this.options.push({ + this.debugOptions.push({ label: name, handler: async () => { await manager.selectConfiguration(undefined, name, undefined, { type }); @@ -205,16 +206,16 @@ export class StartDebugActionViewItem implements IActionViewItem { }); }); - if (this.options.length === 0) { - this.options.push({ label: nls.localize('noConfigurations', "No Configurations"), handler: async () => false }); + if (this.debugOptions.length === 0) { + this.debugOptions.push({ label: nls.localize('noConfigurations', "No Configurations"), handler: async () => false }); } - this.options.push({ label: StartDebugActionViewItem.SEPARATOR, handler: () => Promise.resolve(false) }); - disabledIdxs.push(this.options.length - 1); + this.debugOptions.push({ label: StartDebugActionViewItem.SEPARATOR, handler: () => Promise.resolve(false) }); + disabledIdxs.push(this.debugOptions.length - 1); this.providers.forEach(p => { - this.options.push({ + this.debugOptions.push({ label: `${p.label}...`, handler: async () => { const picked = await p.pick(); @@ -229,7 +230,7 @@ export class StartDebugActionViewItem implements IActionViewItem { manager.getLaunches().filter(l => !l.hidden).forEach(l => { const label = inWorkspace ? nls.localize("addConfigTo", "Add Config ({0})...", l.name) : nls.localize('addConfiguration', "Add Configuration..."); - this.options.push({ + this.debugOptions.push({ label, handler: async () => { await this.commandService.executeCommand(ADD_CONFIGURATION_ID, l.uri.toString()); return false; @@ -237,7 +238,7 @@ export class StartDebugActionViewItem implements IActionViewItem { }); }); - this.selectBox.setOptions(this.options.map((data, index) => { text: data.label, isDisabled: disabledIdxs.indexOf(index) !== -1 }), this.selected); + this.selectBox.setOptions(this.debugOptions.map((data, index) => { text: data.label, isDisabled: disabledIdxs.indexOf(index) !== -1 }), this.selected); } } From 5c005324bb4194e9b7ab0734834b5c16ef16a748 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 16 Feb 2021 18:44:11 +0100 Subject: [PATCH 215/325] tests - enable workspace tests again for now --- scripts/test-integration.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index b1d5e9588e3..537347a6dba 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -68,10 +68,8 @@ after_suite "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR after_suite -# TODO(deepak1556): Disable workspace test temporarily -# https://github.com/microsoft/vscode/issues/111288 -#"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR -#after_suite +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR +after_suite "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR after_suite From 53d2a737761f12dfc86ab871d6d2ad42ed0fa40f Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Tue, 16 Feb 2021 10:48:58 -0800 Subject: [PATCH 216/325] Clean up focused cell styling (fixes #116797) --- src/vs/workbench/contrib/notebook/browser/media/notebook.css | 1 + .../contrib/notebook/browser/notebookEditorWidget.ts | 1 + .../contrib/notebook/browser/view/renderers/cellRenderer.ts | 4 ++-- .../contrib/notebook/browser/viewModel/codeCellViewModel.ts | 4 ++-- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/media/notebook.css b/src/vs/workbench/contrib/notebook/browser/media/notebook.css index 3d015269f38..543decf9627 100644 --- a/src/vs/workbench/contrib/notebook/browser/media/notebook.css +++ b/src/vs/workbench/contrib/notebook/browser/media/notebook.css @@ -287,6 +287,7 @@ position: absolute; width: 1px; height: 100%; + z-index: 1; } /* top border */ diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 6f8e12d51b9..862443a95d5 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -2532,6 +2532,7 @@ registerThemingParticipant((theme, collector) => { collector.addRule(`.notebookOverlay .cell-list-top-cell-toolbar-container { top: -${SCROLLABLE_ELEMENT_PADDING_TOP}px }`); collector.addRule(`.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container { height: ${BOTTOM_CELL_TOOLBAR_HEIGHT}px }`); + collector.addRule(`.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.code-cell-row.focused .cell-focus-indicator-left:before, .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.code-cell-row.focused .cell-focus-indicator-right:before { top: -${CELL_TOP_MARGIN}px; height: calc(100% + ${CELL_TOP_MARGIN + CELL_BOTTOM_MARGIN}px)}`); }); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts index 05567647704..c976351d704 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -266,8 +266,8 @@ abstract class AbstractCellRenderer { if (actions.primary.length || actions.secondary.length) { templateData.container.classList.add('cell-has-toolbar-actions'); if (isCodeCellRenderTemplate(templateData)) { - templateData.focusIndicatorLeft.style.top = `${EDITOR_TOOLBAR_HEIGHT}px`; - templateData.focusIndicatorRight.style.top = `${EDITOR_TOOLBAR_HEIGHT}px`; + templateData.focusIndicatorLeft.style.top = `${EDITOR_TOOLBAR_HEIGHT + CELL_TOP_MARGIN}px`; + templateData.focusIndicatorRight.style.top = `${EDITOR_TOOLBAR_HEIGHT + CELL_TOP_MARGIN}px`; } } else { templateData.container.classList.remove('cell-has-toolbar-actions'); diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts index c59b6d52458..bda35e8bd33 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts @@ -131,7 +131,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod } const statusbarHeight = this.getEditorStatusbarHeight(); - const indicatorHeight = editorHeight + statusbarHeight + outputTotalHeight + outputShowMoreContainerHeight + CELL_TOP_MARGIN + CELL_BOTTOM_MARGIN; + const indicatorHeight = editorHeight + statusbarHeight + outputTotalHeight + outputShowMoreContainerHeight; const outputContainerOffset = EDITOR_TOOLBAR_HEIGHT + CELL_TOP_MARGIN + editorHeight + statusbarHeight; const outputShowMoreContainerOffset = totalHeight - BOTTOM_CELL_TOOLBAR_GAP - BOTTOM_CELL_TOOLBAR_HEIGHT / 2 - outputShowMoreContainerHeight; const bottomToolbarOffset = totalHeight - BOTTOM_CELL_TOOLBAR_GAP - BOTTOM_CELL_TOOLBAR_HEIGHT / 2; @@ -152,7 +152,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod }; } else { outputTotalHeight = this.metadata?.inputCollapsed && this.metadata.outputCollapsed ? 0 : outputTotalHeight; - const indicatorHeight = COLLAPSED_INDICATOR_HEIGHT + outputTotalHeight + outputShowMoreContainerHeight + CELL_TOP_MARGIN + CELL_BOTTOM_MARGIN; + const indicatorHeight = COLLAPSED_INDICATOR_HEIGHT + outputTotalHeight + outputShowMoreContainerHeight; const outputContainerOffset = CELL_TOP_MARGIN + COLLAPSED_INDICATOR_HEIGHT; const totalHeight = CELL_TOP_MARGIN + COLLAPSED_INDICATOR_HEIGHT + CELL_BOTTOM_MARGIN + BOTTOM_CELL_TOOLBAR_GAP + outputTotalHeight + outputShowMoreContainerHeight; const outputShowMoreContainerOffset = totalHeight - BOTTOM_CELL_TOOLBAR_GAP - BOTTOM_CELL_TOOLBAR_HEIGHT / 2 - outputShowMoreContainerHeight; From e091e894b57b205bf9a2b3b3e46c6fab873760e0 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 16 Feb 2021 11:09:17 -0800 Subject: [PATCH 217/325] Include lib in node-pty --- build/.moduleignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/.moduleignore b/build/.moduleignore index cde700b8556..87fab457305 100644 --- a/build/.moduleignore +++ b/build/.moduleignore @@ -72,7 +72,6 @@ keytar/node_modules/** node-pty/binding.gyp node-pty/build/** -node-pty/lib/** node-pty/src/** node-pty/tools/** node-pty/deps/** @@ -80,6 +79,7 @@ node-pty/scripts/** !node-pty/build/Release/*.exe !node-pty/build/Release/*.dll !node-pty/build/Release/*.node +!node-pty/lib/** vscode-nsfw/binding.gyp vscode-nsfw/build/** From 197f453aa9560872370e4b8e4b3b2f9a93c4ad68 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 16 Feb 2021 11:30:42 -0800 Subject: [PATCH 218/325] Show tailored notification when paste isn't supported --- src/vs/workbench/contrib/terminal/browser/terminalView.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalView.ts b/src/vs/workbench/contrib/terminal/browser/terminalView.ts index 7674a991804..3e3dafe4c3c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalView.ts @@ -35,6 +35,7 @@ import { attachSelectBoxStyler, attachStylerCallback } from 'vs/platform/theme/c import { selectBorder } from 'vs/platform/theme/common/colorRegistry'; import { ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox'; import { equals } from 'vs/base/common/arrays'; +import { BrowserFeatures } from 'vs/base/browser/canIUse'; const FIND_FOCUS_CLASS = 'find-focused'; @@ -244,7 +245,11 @@ export class TerminalViewPane extends ViewPane { await terminal.copySelection(); terminal.clearSelection(); } else { - terminal.paste(); + if (!BrowserFeatures.clipboard.readText) { + terminal.paste(); + } else { + this._notificationService.info('This browser doesn\'t support the clipboard.readText API needed to trigger a paste'); + } } // Clear selection after all click event bubbling is finished on Mac to prevent // right-click selecting a word which is seemed cannot be disabled. There is a From 939038aae9ad08786aa199cf14d9c742dbe2f6dd Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 16 Feb 2021 11:35:19 -0800 Subject: [PATCH 219/325] Recursively include lib --- build/.moduleignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/.moduleignore b/build/.moduleignore index 87fab457305..2ec120dbdde 100644 --- a/build/.moduleignore +++ b/build/.moduleignore @@ -79,7 +79,7 @@ node-pty/scripts/** !node-pty/build/Release/*.exe !node-pty/build/Release/*.dll !node-pty/build/Release/*.node -!node-pty/lib/** +!node-pty/lib/**/* vscode-nsfw/binding.gyp vscode-nsfw/build/** From 14923b5427a1747d39e14a84d70780218ad7022f Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 16 Feb 2021 12:12:22 -0800 Subject: [PATCH 220/325] Allow conoutSocketWorker in unpacked asar --- build/.moduleignore | 2 +- build/gulpfile.vscode.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/.moduleignore b/build/.moduleignore index 2ec120dbdde..04cf1f574bb 100644 --- a/build/.moduleignore +++ b/build/.moduleignore @@ -79,7 +79,7 @@ node-pty/scripts/** !node-pty/build/Release/*.exe !node-pty/build/Release/*.dll !node-pty/build/Release/*.node -!node-pty/lib/**/* +!node-pty/lib/worker/** vscode-nsfw/binding.gyp vscode-nsfw/build/** diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index e3ca3514bb6..28c60c1fad9 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -228,7 +228,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op .pipe(jsFilter) .pipe(util.rewriteSourceMappingURL(sourceMappingURLBase)) .pipe(jsFilter.restore) - .pipe(createAsar(path.join(process.cwd(), 'node_modules'), ['**/*.node', '**/vscode-ripgrep/bin/*', '**/node-pty/build/Release/*', '**/*.wasm'], 'node_modules.asar')); + .pipe(createAsar(path.join(process.cwd(), 'node_modules'), ['**/*.node', '**/vscode-ripgrep/bin/*', '**/node-pty/build/Release/*', '**/node-pty/lib/worker/*', '**/*.wasm'], 'node_modules.asar')); let all = es.merge( packageJsonStream, From c41fb762991bfc61082a92ca887389379b0d52fc Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 16 Feb 2021 12:13:39 -0800 Subject: [PATCH 221/325] Re-enable all tests --- .../src/singlefolder-tests/terminal.test.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index ec01fb7c560..c28ece13fd1 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -131,7 +131,7 @@ import { assertNoRpc } from '../utils'; }); }); - test.skip('processId immediately after createTerminal should fetch the pid', async () => { + test('processId immediately after createTerminal should fetch the pid', async () => { const terminal = window.createTerminal(); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -153,7 +153,7 @@ import { assertNoRpc } from '../utils'; }); }); - test.skip('name in constructor should set terminal.name', async () => { + test('name in constructor should set terminal.name', async () => { const terminal = window.createTerminal('a'); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -173,7 +173,7 @@ import { assertNoRpc } from '../utils'; }); }); - test.skip('creationOptions should be set and readonly for TerminalOptions terminals', async () => { + test('creationOptions should be set and readonly for TerminalOptions terminals', async () => { const options = { name: 'foo', hideFromUser: true @@ -199,7 +199,7 @@ import { assertNoRpc } from '../utils'; throws(() => terminalOptions.name = 'bad', 'creationOptions should be readonly at runtime'); }); - test.skip('onDidOpenTerminal should fire when a terminal is created', async () => { + test('onDidOpenTerminal should fire when a terminal is created', async () => { const terminal = window.createTerminal('b'); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -219,7 +219,7 @@ import { assertNoRpc } from '../utils'; }); }); - test.skip('exitStatus.code should be set to undefined after a terminal is disposed', async () => { + test('exitStatus.code should be set to undefined after a terminal is disposed', async () => { const terminal = window.createTerminal(); const result = await new Promise(r => { disposables.push(window.onDidOpenTerminal(t => { @@ -310,7 +310,7 @@ import { assertNoRpc } from '../utils'; // terminal1.show(); // }); - suite.skip('hideFromUser', () => { + suite('hideFromUser', () => { test('should be available to terminals API', async () => { const terminal = window.createTerminal({ name: 'bg', hideFromUser: true }); const result = await new Promise(r => { @@ -645,7 +645,7 @@ import { assertNoRpc } from '../utils'; }); }); - suite.skip('environmentVariableCollection', () => { + suite('environmentVariableCollection', () => { test('should have collection variables apply to terminals immediately after setting', (done) => { // Text to match on before passing the test const expectedText = [ From e7d2a864e4a7e4c82ef7901559beeacd9bf8a0da Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 16 Feb 2021 12:48:16 -0800 Subject: [PATCH 222/325] testing: add contextual commands for running tests Fixes #116589 --- src/vs/base/common/map.ts | 82 +++++++++ src/vs/base/test/common/map.test.ts | 30 +++- .../hierarchalByLocation.ts | 25 +-- .../testing/browser/testExplorerActions.ts | 159 +++++++++++++++++- .../testing/browser/testing.contribution.ts | 4 + .../testing/common/testResultService.ts | 22 ++- 6 files changed, 305 insertions(+), 17 deletions(-) diff --git a/src/vs/base/common/map.ts b/src/vs/base/common/map.ts index 0e08876e537..685cbaa95e4 100644 --- a/src/vs/base/common/map.ts +++ b/src/vs/base/common/map.ts @@ -1048,3 +1048,85 @@ export class LRUCache extends LinkedMap { } } } + +type IndexRecord = [fn: (value: V) => R, map: Map]; + +/** + * Map that supports multiple indicies whose keys are derived from the value. + */ +export class IndexedSet implements Set { + public get size() { + return this.source.size; + } + + private source = new Set(); + private readonly indexes: IndexRecord[] = []; + + /** + * Creates a map that maintains a copy of the items in the set, indexed + * by the given 'indexer' function. + */ + index(indexer: (value: V) => R) { + const map = new Map(); + for (const value of this.source) { + map.set(indexer(value), value); + } + + this.indexes.push([indexer, map]); + return map as ReadonlyMap; + } + + add(value: V): this { + this.source.add(value); + for (const [index, map] of this.indexes) { + map.set(index(value), value); + } + + return this; + } + + clear(): void { + this.source.clear(); + for (const [, map] of this.indexes) { + map.clear(); + } + } + + delete(value: V): boolean { + if (!this.source.delete(value)) { + return false; + } + + for (const [index, map] of this.indexes) { + map.delete(index(value)); + } + + return true; + } + + forEach(callbackfn: (value: V, value2: V, set: Set) => void, thisArg?: any): void { + this.source.forEach(callbackfn, thisArg); + } + + has(value: V): boolean { + return this.source.has(value); + } + + [Symbol.toStringTag]: string; + + values(): IterableIterator { + return this.source.values(); + } + + entries(): IterableIterator<[V, V]> { + return this.source.entries(); + } + + keys(): IterableIterator { + return this.source.keys(); + } + + [Symbol.iterator](): IterableIterator { + return this.source.values(); + } +} diff --git a/src/vs/base/test/common/map.test.ts b/src/vs/base/test/common/map.test.ts index f157455531a..0c9fc51e097 100644 --- a/src/vs/base/test/common/map.test.ts +++ b/src/vs/base/test/common/map.test.ts @@ -4,9 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { ResourceMap, TernarySearchTree, PathIterator, StringIterator, LinkedMap, Touch, LRUCache, UriIterator, ConfigKeysIterator } from 'vs/base/common/map'; -import { URI } from 'vs/base/common/uri'; +import { ConfigKeysIterator, IndexedSet, LinkedMap, LRUCache, PathIterator, ResourceMap, StringIterator, TernarySearchTree, Touch, UriIterator } from 'vs/base/common/map'; import { extUriIgnorePathCase } from 'vs/base/common/resources'; +import { URI } from 'vs/base/common/uri'; suite('Map', () => { @@ -1020,4 +1020,30 @@ suite('Map', () => { assert.strictEqual(map.get(windowsFile), 'true'); assert.strictEqual(map.get(uncFile), 'true'); }); + + test('IndexedSet - add', () => { + const i = new IndexedSet(); + i.add(2); + const map = i.index(v => v ** 2); + assert.deepStrictEqual(map, new Map([[4, 2]])); + + i.add(3); + assert.deepStrictEqual(map, new Map([[9, 3], [4, 2]])); + }); + + test('IndexedSet - delete', () => { + const i = new IndexedSet(); + const map = i.index(v => v ** 2); + i.add(2); + i.delete(2); + assert.deepStrictEqual(map, new Map([])); + }); + + test('IndexedSet - clear', () => { + const i = new IndexedSet(); + const map = i.index(v => v ** 2); + i.add(2); + i.clear(); + assert.deepStrictEqual(map, new Map([])); + }); }); diff --git a/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation.ts b/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation.ts index 47cbf47ad77..6cab52d3a1b 100644 --- a/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation.ts +++ b/src/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation.ts @@ -7,6 +7,7 @@ import { ObjectTree } from 'vs/base/browser/ui/tree/objectTree'; import { Emitter } from 'vs/base/common/event'; import { FuzzyScore } from 'vs/base/common/filters'; import { Disposable } from 'vs/base/common/lifecycle'; +import { IndexedSet } from 'vs/base/common/map'; import { URI } from 'vs/base/common/uri'; import { Position } from 'vs/editor/common/core/position'; import { IWorkspaceFolder, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; @@ -39,11 +40,13 @@ export class HierarchicalByLocationProjection extends Disposable implements ITes private readonly updateEmitter = new Emitter(); private readonly changes = new NodeChangeList(); private readonly locations = new TestLocationStore(); + private readonly itemSource = new IndexedSet(); + private readonly itemsByExtId = this.itemSource.index(v => v.test.item.extId); /** * Map of item IDs to test item objects. */ - protected readonly items = new Map(); + protected readonly items = this.itemSource.index(v => v.test.id); /** * Root folders @@ -82,15 +85,13 @@ export class HierarchicalByLocationProjection extends Disposable implements ITes // when test states change, reflect in the tree // todo: optimize this to avoid needing to iterate this._register(results.onTestChanged(({ item: result }) => { - for (const i of this.items.values()) { - if (i.test.item.extId === result.item.extId) { - i.ownState = result.state.state; - i.retired = result.retired; - refreshComputedState(computedStateAccessor, i, this.addUpdated, result.computedState); - this.addUpdated(i); - this.updateEmitter.fire(); - return; - } + const item = this.itemsByExtId.get(result.item.extId); + if (item) { + item.ownState = result.state.state; + item.retired = result.retired; + refreshComputedState(computedStateAccessor, item, this.addUpdated, result.computedState); + this.addUpdated(item); + this.updateEmitter.fire(); } })); @@ -219,14 +220,14 @@ export class HierarchicalByLocationProjection extends Disposable implements ITes protected unstoreItem(item: HierarchicalElement) { item.parentItem.children.delete(item); - this.items.delete(item.test.id); + this.itemSource.delete(item); this.locations.remove(item); return item.children; } protected storeItem(item: HierarchicalElement) { item.parentItem.children.add(item); - this.items.set(item.test.id, item); + this.itemSource.add(item); this.locations.add(item); const prevState = this.results.getStateByExtId(item.test.item.extId)?.[1]; diff --git a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts index 2dac0056fb6..52f558c3f00 100644 --- a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts +++ b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts @@ -25,6 +25,7 @@ import { TestExplorerViewMode, TestExplorerViewSorting, Testing } from 'vs/workb import { InternalTestItem, TestIdWithProvider } from 'vs/workbench/contrib/testing/common/testCollection'; import { ITestingAutoRun } from 'vs/workbench/contrib/testing/common/testingAutoRun'; import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys'; +import { isFailedState } from 'vs/workbench/contrib/testing/common/testingStates'; import { ITestResult, ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService'; import { ITestService, waitForAllRoots, waitForAllTests } from 'vs/workbench/contrib/testing/common/testService'; import { IWorkspaceTestCollectionService } from 'vs/workbench/contrib/testing/common/workspaceTestCollectionService'; @@ -593,7 +594,6 @@ export class DebugAtCursor extends RunOrDebugAtCursor { } } - abstract class RunOrDebugCurrentFile extends Action2 { /** * @override @@ -667,3 +667,160 @@ export class DebugCurrentFile extends RunOrDebugCurrentFile { return service.runTests({ debug: true, tests: nodes.map(node => ({ testId: node.id, providerId: node.providerId })) }); } } + +abstract class RunOrDebugTestResults extends Action2 { + /** + * @override + */ + public async run(accessor: ServicesAccessor) { + const testService = accessor.get(ITestService); + const extIds = this.getTestExtIdsToRun(accessor); + if (extIds.size === 0) { + return; + } + + const workspaceTests = accessor.get(IWorkspaceTestCollectionService).subscribeToWorkspaceTests(); + + try { + await Promise.all(workspaceTests.workspaceFolderCollections.map(([, c]) => waitForAllTests(c))); + + const toRun: InternalTestItem[] = []; + for (const [, collection] of workspaceTests.workspaceFolderCollections) { + for (const node of collection.all) { + if (extIds.has(node.item.extId) && this.filter(node)) { + toRun.push(node); + extIds.delete(node.item.extId); + } + } + } + + await this.runTest(testService, toRun); + } finally { + workspaceTests.dispose(); + } + } + + protected abstract getTestExtIdsToRun(accessor: ServicesAccessor): Set; + + protected abstract filter(node: InternalTestItem): boolean; + + protected abstract runTest(service: ITestService, node: InternalTestItem[]): Promise; +} + +abstract class RunOrDebugFailedTests extends RunOrDebugTestResults { + /** + * @inheritdoc + */ + protected getTestExtIdsToRun(accessor: ServicesAccessor): Set { + const { results } = accessor.get(ITestResultService); + const extIds = new Set(); + for (let i = results.length - 1; i >= 0; i--) { + for (const test of results[i].tests) { + if (isFailedState(test.state.state)) { + extIds.add(test.item.extId); + } else { + extIds.delete(test.item.extId); + } + } + } + + return extIds; + } +} + +abstract class RunOrDebugLastRun extends RunOrDebugTestResults { + /** + * @inheritdoc + */ + protected getTestExtIdsToRun(accessor: ServicesAccessor): Set { + const lastResult = accessor.get(ITestResultService).results[0]; + const extIds = new Set(); + if (!lastResult) { + return extIds; + } + + for (const test of lastResult.tests) { + if (test.direct) { + extIds.add(test.item.extId); + } + } + + return extIds; + } +} + +export class ReRunFailedTests extends RunOrDebugFailedTests { + constructor() { + super({ + id: 'testing.reRunFailTests', + title: localize('testing.reRunFailTests', "Re-run Failed Tests"), + f1: true, + category, + }); + } + + protected filter(node: InternalTestItem): boolean { + return node.item.runnable; + } + + protected runTest(service: ITestService, nodes: InternalTestItem[]): Promise { + return service.runTests({ debug: false, tests: nodes.map(node => ({ testId: node.id, providerId: node.providerId })) }); + } +} + +export class DebugFailedTests extends RunOrDebugFailedTests { + constructor() { + super({ + id: 'testing.debugFailTests', + title: localize('testing.debugFailTests', "Debug Failed Tests"), + f1: true, + category, + }); + } + + protected filter(node: InternalTestItem): boolean { + return node.item.debuggable; + } + + protected runTest(service: ITestService, nodes: InternalTestItem[]): Promise { + return service.runTests({ debug: true, tests: nodes.map(node => ({ testId: node.id, providerId: node.providerId })) }); + } +} + +export class ReRunLastRun extends RunOrDebugLastRun { + constructor() { + super({ + id: 'testing.reRunLastRun', + title: localize('testing.reRunLastRun', "Re-run Last Run"), + f1: true, + category, + }); + } + + protected filter(node: InternalTestItem): boolean { + return node.item.runnable; + } + + protected runTest(service: ITestService, nodes: InternalTestItem[]): Promise { + return service.runTests({ debug: false, tests: nodes.map(node => ({ testId: node.id, providerId: node.providerId })) }); + } +} + +export class DebugLastRun extends RunOrDebugLastRun { + constructor() { + super({ + id: 'testing.debugLastRun', + title: localize('testing.debugLastRun', "Debug Last Run"), + f1: true, + category, + }); + } + + protected filter(node: InternalTestItem): boolean { + return node.item.debuggable; + } + + protected runTest(service: ITestService, nodes: InternalTestItem[]): Promise { + return service.runTests({ debug: true, tests: nodes.map(node => ({ testId: node.id, providerId: node.providerId })) }); + } +} diff --git a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts index 6ef650fcedf..411a66f1fa6 100644 --- a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts +++ b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts @@ -101,6 +101,10 @@ registerAction2(Action.DebugAtCursor); registerAction2(Action.RunAtCursor); registerAction2(Action.DebugCurrentFile); registerAction2(Action.RunCurrentFile); +registerAction2(Action.ReRunFailedTests); +registerAction2(Action.DebugFailedTests); +registerAction2(Action.ReRunLastRun); +registerAction2(Action.DebugLastRun); registerAction2(CloseTestPeek); Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TestingContentProvider, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/testing/common/testResultService.ts b/src/vs/workbench/contrib/testing/common/testResultService.ts index c380e53708b..6cc3d553a54 100644 --- a/src/vs/workbench/contrib/testing/common/testResultService.ts +++ b/src/vs/workbench/contrib/testing/common/testResultService.ts @@ -56,6 +56,11 @@ export interface ITestResult { */ readonly isAutoRun?: boolean; + /** + * Gets all tests involved in the run. + */ + tests: IterableIterator; + /** * Gets the state of the test by its extension-assigned ID. */ @@ -147,6 +152,7 @@ const makeNodeAndChildren = ( test: IncrementalTestCollectionItem, byExtId: Map, byInternalId: Map, + isExecutedDirectly = true, ): TestResultItem => { const existing = byInternalId.get(test.id); if (existing) { @@ -154,10 +160,14 @@ const makeNodeAndChildren = ( } const mapped = itemToNode(test, byExtId, byInternalId); + if (isExecutedDirectly) { + mapped.direct = true; + } + for (const childId of test.children) { const child = collection.getNodeById(childId); if (child) { - makeNodeAndChildren(collection, child, byExtId, byInternalId); + makeNodeAndChildren(collection, child, byExtId, byInternalId, false); } } @@ -173,6 +183,7 @@ export interface TestResultItem extends IncrementalTestCollectionItem { state: ITestState; computedState: TestRunState; retired: boolean; + direct?: true; } /** @@ -230,7 +241,7 @@ export class LiveTestResult implements ITestResult { public readonly counts: { [K in TestRunState]: number } = makeEmptyCounts(); /** - * Gets all tests involved in the run by ID. + * @inheritdoc */ public get tests() { return this.testByInternalId.values(); @@ -420,6 +431,13 @@ class HydratedTestResult implements ITestResult { */ public readonly isComplete = true; + /** + * @inheritdoc + */ + public get tests() { + return this.byExtId.values(); + } + private readonly byExtId = new Map(); constructor(private readonly serialized: ISerializedResults) { From 6f23480f3b1e45ff3d755cc73bd84c5da68db7ef Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 16 Feb 2021 12:53:29 -0800 Subject: [PATCH 223/325] Remove bundling changes --- build/.moduleignore | 1 - build/gulpfile.vscode.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/build/.moduleignore b/build/.moduleignore index 04cf1f574bb..d1f9194ba2a 100644 --- a/build/.moduleignore +++ b/build/.moduleignore @@ -79,7 +79,6 @@ node-pty/scripts/** !node-pty/build/Release/*.exe !node-pty/build/Release/*.dll !node-pty/build/Release/*.node -!node-pty/lib/worker/** vscode-nsfw/binding.gyp vscode-nsfw/build/** diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 28c60c1fad9..e3ca3514bb6 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -228,7 +228,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op .pipe(jsFilter) .pipe(util.rewriteSourceMappingURL(sourceMappingURLBase)) .pipe(jsFilter.restore) - .pipe(createAsar(path.join(process.cwd(), 'node_modules'), ['**/*.node', '**/vscode-ripgrep/bin/*', '**/node-pty/build/Release/*', '**/node-pty/lib/worker/*', '**/*.wasm'], 'node_modules.asar')); + .pipe(createAsar(path.join(process.cwd(), 'node_modules'), ['**/*.node', '**/vscode-ripgrep/bin/*', '**/node-pty/build/Release/*', '**/*.wasm'], 'node_modules.asar')); let all = es.merge( packageJsonStream, From 52d1b626f3139b786f1fe592037ab5c02e37cdae Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 16 Feb 2021 14:05:49 -0800 Subject: [PATCH 224/325] Pick up latest TS version for building VS Code --- package.json | 2 +- .../base/browser/ui/dropdown/dropdownActionViewItem.ts | 5 ++++- src/vs/editor/common/modes/languageFeatureRegistry.ts | 4 ++-- src/vs/editor/common/modes/languageSelector.ts | 2 +- src/vs/workbench/api/common/extHost.api.impl.ts | 5 +++-- src/vs/workbench/api/common/extHostTypeConverters.ts | 9 +++++---- .../contrib/files/browser/views/explorerViewer.ts | 2 +- .../extensions/common/abstractExtensionService.ts | 10 +++++----- .../workbench/services/extensions/common/extensions.ts | 4 ++-- yarn.lock | 10 +++++----- 10 files changed, 29 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 3b0ce899f1c..1669245e977 100644 --- a/package.json +++ b/package.json @@ -190,7 +190,7 @@ "style-loader": "^1.0.0", "ts-loader": "^6.2.1", "tsec": "0.1.3", - "typescript": "4.2.0-dev.20201207", + "typescript": "^4.3.0-dev.20210216", "typescript-formatter": "7.1.0", "underscore": "^1.8.2", "vinyl": "^2.0.0", diff --git a/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts b/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts index 2aaac8a7ab3..5b46a52a549 100644 --- a/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts +++ b/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts @@ -172,7 +172,10 @@ export class ActionWithDropdownActionViewItem extends ActionViewItem { const menuActionsProvider = { getActions: () => { const actionsProvider = (this.options).menuActionsOrProvider; - return [this._action, ...(Array.isArray(actionsProvider) ? actionsProvider : actionsProvider.getActions())]; + return [this._action, ...(Array.isArray(actionsProvider) + ? actionsProvider + : (actionsProvider as IActionProvider).getActions()) // TODO: microsoft/TypeScript#42768 + ]; } }; this.dropdownMenuActionViewItem = new DropdownMenuActionViewItem(this._register(new Action('dropdownAction', undefined)), menuActionsProvider, this.contextMenuProvider, { classNames: ['dropdown', ...Codicon.dropDownButton.classNamesArray, ...(this.options).menuActionClassNames || []] }); diff --git a/src/vs/editor/common/modes/languageFeatureRegistry.ts b/src/vs/editor/common/modes/languageFeatureRegistry.ts index b5cd1ca4a75..7dec322f53f 100644 --- a/src/vs/editor/common/modes/languageFeatureRegistry.ts +++ b/src/vs/editor/common/modes/languageFeatureRegistry.ts @@ -9,7 +9,7 @@ import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { LRUCache } from 'vs/base/common/map'; import { MovingAverage } from 'vs/base/common/numbers'; import { ITextModel } from 'vs/editor/common/model'; -import { LanguageSelector, score } from 'vs/editor/common/modes/languageSelector'; +import { LanguageFilter, LanguageSelector, score } from 'vs/editor/common/modes/languageSelector'; import { shouldSynchronizeModel } from 'vs/editor/common/services/modelService'; interface Entry { @@ -25,7 +25,7 @@ function isExclusive(selector: LanguageSelector): boolean { } else if (Array.isArray(selector)) { return selector.every(isExclusive); } else { - return !!selector.exclusive; + return !!(selector as LanguageFilter).exclusive; // TODO: microsoft/TypeScript#42768 } } diff --git a/src/vs/editor/common/modes/languageSelector.ts b/src/vs/editor/common/modes/languageSelector.ts index eff5d35ab30..02826877fdc 100644 --- a/src/vs/editor/common/modes/languageSelector.ts +++ b/src/vs/editor/common/modes/languageSelector.ts @@ -55,7 +55,7 @@ export function score(selector: LanguageSelector | undefined, candidateUri: URI, } else if (selector) { // filter -> select accordingly, use defaults for scheme - const { language, pattern, scheme, hasAccessToAllModels } = selector; + const { language, pattern, scheme, hasAccessToAllModels } = selector as LanguageFilter; // TODO: microsoft/TypeScript#42768 if (!candidateIsSynchronized && !hasAccessToAllModels) { return 0; diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 45af435ed3d..9b95c71438e 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -198,10 +198,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I } else if (typeof selector === 'string') { informOnce(selector); } else { - if (typeof selector.scheme === 'undefined') { + const filter = selector as vscode.DocumentFilter; // TODO: microsoft/TypeScript#42768 + if (typeof filter.scheme === 'undefined') { informOnce(selector); } - if (!extension.enableProposedApi && typeof selector.exclusive === 'boolean') { + if (!extension.enableProposedApi && typeof filter.exclusive === 'boolean') { throwProposedApiError(extension); } } diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index d3afe4eb214..8b57657a364 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -1394,11 +1394,12 @@ export namespace LanguageSelector { } else if (typeof selector === 'string') { return selector; } else { + const filter = selector as vscode.DocumentFilter; // TODO: microsoft/TypeScript#42768 return { - language: selector.language, - scheme: selector.scheme, - pattern: typeof selector.pattern === 'undefined' ? undefined : GlobPattern.from(selector.pattern), - exclusive: selector.exclusive + language: filter.language, + scheme: filter.scheme, + pattern: typeof filter.pattern === 'undefined' ? undefined : GlobPattern.from(filter.pattern), + exclusive: filter.exclusive }; } } diff --git a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts index 6bf781d2e31..67fdc77b546 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts @@ -1229,7 +1229,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop { res = await reader.read(); } - writeableStream.end(res.value instanceof Uint8Array ? VSBuffer.wrap(res.value) : undefined); + writeableStream.end(undefined); } catch (error) { writeableStream.end(error); } diff --git a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts index c8742070a12..94f39dc0dbf 100644 --- a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts +++ b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts @@ -21,7 +21,7 @@ import { ExtensionMessageCollector, ExtensionPoint, ExtensionsRegistry, IExtensi import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry'; import { ResponsiveState } from 'vs/workbench/services/extensions/common/rpcProtocol'; import { ExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManager'; -import { ExtensionIdentifier, IExtensionDescription, ExtensionType, ITranslatedScannedExtension, IExtension, ExtensionKind } from 'vs/platform/extensions/common/extensions'; +import { ExtensionIdentifier, IExtensionDescription, ExtensionType, ITranslatedScannedExtension, IExtension, ExtensionKind, IExtensionContributions } from 'vs/platform/extensions/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions'; import { IProductService } from 'vs/platform/product/common/productService'; @@ -535,14 +535,14 @@ export abstract class AbstractExtensionService extends Disposable implements IEx }); } - public readExtensionPointContributions(extPoint: IExtensionPoint): Promise[]> { + public readExtensionPointContributions(extPoint: IExtensionPoint): Promise[]> { return this._installedExtensionsReady.wait().then(() => { const availableExtensions = this._registry.getAllExtensionDescriptions(); const result: ExtensionPointContribution[] = []; for (const desc of availableExtensions) { if (desc.contributes && hasOwnProperty.call(desc.contributes, extPoint.name)) { - result.push(new ExtensionPointContribution(desc, desc.contributes[extPoint.name as keyof typeof desc.contributes])); + result.push(new ExtensionPointContribution(desc, desc.contributes[extPoint.name as keyof typeof desc.contributes] as T)); } } @@ -691,13 +691,13 @@ export abstract class AbstractExtensionService extends Disposable implements IEx } } - private static _handleExtensionPoint(extensionPoint: ExtensionPoint, availableExtensions: IExtensionDescription[], messageHandler: (msg: IMessage) => void): void { + private static _handleExtensionPoint(extensionPoint: ExtensionPoint, availableExtensions: IExtensionDescription[], messageHandler: (msg: IMessage) => void): void { const users: IExtensionPointUser[] = []; for (const desc of availableExtensions) { if (desc.contributes && hasOwnProperty.call(desc.contributes, extensionPoint.name)) { users.push({ description: desc, - value: desc.contributes[extensionPoint.name as keyof typeof desc.contributes], + value: desc.contributes[extensionPoint.name as keyof typeof desc.contributes] as T, collector: new ExtensionMessageCollector(messageHandler, desc, extensionPoint.name) }); } diff --git a/src/vs/workbench/services/extensions/common/extensions.ts b/src/vs/workbench/services/extensions/common/extensions.ts index 33883bedb25..ed224cb6eca 100644 --- a/src/vs/workbench/services/extensions/common/extensions.ts +++ b/src/vs/workbench/services/extensions/common/extensions.ts @@ -8,7 +8,7 @@ import Severity from 'vs/base/common/severity'; import { URI } from 'vs/base/common/uri'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionPoint } from 'vs/workbench/services/extensions/common/extensionsRegistry'; -import { ExtensionIdentifier, IExtension, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { ExtensionIdentifier, IExtension, ExtensionType, IExtensionDescription, IExtensionContributions } from 'vs/platform/extensions/common/extensions'; import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator'; @@ -224,7 +224,7 @@ export interface IExtensionService { /** * Read all contributions to an extension point. */ - readExtensionPointContributions(extPoint: IExtensionPoint): Promise[]>; + readExtensionPointContributions(extPoint: IExtensionPoint): Promise[]>; /** * Get information about extensions status. diff --git a/yarn.lock b/yarn.lock index 8695942fcec..4fbbc3752b8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9687,11 +9687,6 @@ typescript-formatter@7.1.0: commandpost "^1.0.0" editorconfig "^0.15.0" -typescript@4.2.0-dev.20201207: - version "4.2.0-dev.20201207" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.0-dev.20201207.tgz#19a34bc7d2d42a7467c512c63f135587ac848807" - integrity sha512-fPHBDi/fgdX4WiRC7cFVv/aL069PgUaDWuLYUSHatWZujz/Lkc9bkf/zL3rKdNSCxlNKAMs3fhJv/yompOphZA== - typescript@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4" @@ -9702,6 +9697,11 @@ typescript@^3.0.1: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== +typescript@^4.3.0-dev.20210216: + version "4.3.0-dev.20210216" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.0-dev.20210216.tgz#233327e6094008c02265ba140f8d9ece9133421e" + integrity sha512-pJLcC/kqnE+0rftTRc2/gYBkz9nl+kJfaU8sSOLYnzUvD8p+LOZMzXfaLoKPdGFJ6U9+Ox/sYV9HBTJVEjSTYg== + typical@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" From 2cc13674e3308f08664d0b4a93d8e28df51a7bbc Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 16 Feb 2021 14:09:38 -0800 Subject: [PATCH 225/325] Also bump build version and run formatter on all files --- build/package.json | 2 +- build/yarn.lock | 10 +++++----- src/vs/workbench/common/editor.ts | 6 +++--- .../workbench/contrib/debug/browser/breakpointsView.ts | 10 +++++----- .../test/electron-browser/api/extHostSearch.test.ts | 8 ++++---- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/build/package.json b/build/package.json index 7de0c8f734c..a6ece3f020f 100644 --- a/build/package.json +++ b/build/package.json @@ -51,7 +51,7 @@ "p-limit": "^3.1.0", "plist": "^3.0.1", "source-map": "0.6.1", - "typescript": "4.2.0-dev.20201207", + "typescript": "^4.3.0-dev.20210216", "vsce": "1.48.0", "vscode-universal": "deepak1556/universal#61454d96223b774c53cda10f72c2098c0ce02d58" }, diff --git a/build/yarn.lock b/build/yarn.lock index a111c831be1..28014afaad9 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -1695,16 +1695,16 @@ typed-rest-client@^0.9.0: tunnel "0.0.4" underscore "1.8.3" -typescript@4.2.0-dev.20201207: - version "4.2.0-dev.20201207" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.0-dev.20201207.tgz#19a34bc7d2d42a7467c512c63f135587ac848807" - integrity sha512-fPHBDi/fgdX4WiRC7cFVv/aL069PgUaDWuLYUSHatWZujz/Lkc9bkf/zL3rKdNSCxlNKAMs3fhJv/yompOphZA== - typescript@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7" integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg== +typescript@^4.3.0-dev.20210216: + version "4.3.0-dev.20210216" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.0-dev.20210216.tgz#233327e6094008c02265ba140f8d9ece9133421e" + integrity sha512-pJLcC/kqnE+0rftTRc2/gYBkz9nl+kJfaU8sSOLYnzUvD8p+LOZMzXfaLoKPdGFJ6U9+Ox/sYV9HBTJVEjSTYg== + uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.5.tgz#0c65f15f815aa08b560a61ce8b4db7ffc3f45376" diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 5471bd95d6f..9feceb6188b 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -1549,9 +1549,9 @@ export async function pathsToEditors(paths: IPathData[] | undefined, fileService pinned: true, override: path.overrideId } : { - pinned: true, - override: path.overrideId - }; + pinned: true, + override: path.overrideId + }; let input: IResourceEditorInput | IUntitledTextResourceEditorInput; if (!exists) { diff --git a/src/vs/workbench/contrib/debug/browser/breakpointsView.ts b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts index eca16433e3b..07ed0eec5e9 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointsView.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts @@ -856,11 +856,11 @@ export function openBreakpointSource(breakpoint: IBreakpoint, sideBySide: boolea startColumn: breakpoint.column || 1, endColumn: breakpoint.endColumn || Constants.MAX_SAFE_SMALL_INTEGER } : { - startLineNumber: breakpoint.lineNumber, - startColumn: breakpoint.column || 1, - endLineNumber: breakpoint.lineNumber, - endColumn: breakpoint.column || Constants.MAX_SAFE_SMALL_INTEGER - }; + startLineNumber: breakpoint.lineNumber, + startColumn: breakpoint.column || 1, + endLineNumber: breakpoint.lineNumber, + endColumn: breakpoint.column || Constants.MAX_SAFE_SMALL_INTEGER + }; return editorService.openEditor({ resource: breakpoint.uri, diff --git a/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts b/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts index 1935dbb5adc..e5c69a38e4e 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts @@ -713,10 +713,10 @@ suite('ExtHostSearch', () => { match: null // Don't care about this right now } } : { - uri: r.uri.toString(), - text: r.text, - lineNumber: r.lineNumber - }); + uri: r.uri.toString(), + text: r.text, + lineNumber: r.lineNumber + }); return assert.deepEqual( makeComparable(actualTextSearchResults), From 7459443550449afa07ec43da67b52b8ea03568d0 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 16 Feb 2021 14:28:34 -0800 Subject: [PATCH 226/325] Update monaco.d.ts --- src/vs/monaco.d.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 5b0421be3f5..4aa4fc84b84 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -4080,12 +4080,12 @@ declare namespace monaco.editor { accessibilitySupport: IEditorOption; accessibilityPageSize: IEditorOption; ariaLabel: IEditorOption; - autoClosingBrackets: IEditorOption; - autoClosingOvertype: IEditorOption; - autoClosingQuotes: IEditorOption; + autoClosingBrackets: IEditorOption; + autoClosingOvertype: IEditorOption; + autoClosingQuotes: IEditorOption; autoIndent: IEditorOption; automaticLayout: IEditorOption; - autoSurround: IEditorOption; + autoSurround: IEditorOption; stickyTabStops: IEditorOption; codeLens: IEditorOption; codeLensFontFamily: IEditorOption; From 12677674727e9fda5f57fd06fb363cb9275a5495 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 16 Feb 2021 14:57:40 -0800 Subject: [PATCH 227/325] fix #116598. broadcast output items change. --- .../src/singlefolder-tests/notebook.test.ts | 28 +++++++++++++++++++ .../api/common/extHostNotebookDocument.ts | 21 +++++++++++++- .../common/model/notebookTextModel.ts | 16 +++++++++++ .../contrib/notebook/common/notebookCommon.ts | 19 +++++++++---- 4 files changed, 78 insertions(+), 6 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts index b437120c23c..80b241e0322 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts @@ -1460,6 +1460,34 @@ suite('Notebook API tests', function () { await vscode.commands.executeCommand('workbench.action.closeAllEditors'); }); + + test('#116598, output items change event.', async function () { + assertInitalState(); + + const resource = await createRandomFile('', undefined, '.vsctestnb'); + await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); + + const edit = new vscode.WorkspaceEdit(); + edit.appendNotebookCellOutput(resource, 0, [new vscode.NotebookCellOutput([ + new vscode.NotebookCellOutputItem('application/foo', 'bar'), + new vscode.NotebookCellOutputItem('application/json', { data: true }, { metadata: true }), + ])]); + await vscode.workspace.applyEdit(edit); + assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells[0].outputs.length, 1); + assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells[0].outputs[0].outputs.length, 2); + + const appendEdit = new vscode.WorkspaceEdit(); + const newItem = new vscode.NotebookCellOutputItem('text/plain', '1'); + appendEdit.appendNotebookCellOutputItems( + resource, + 0, + vscode.window.activeNotebookEditor!.document.cells[0].outputs[0].id, + [newItem] + ); + await vscode.workspace.applyEdit(appendEdit); + assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells[0].outputs[0].outputs.length, 3); + assert.deepStrictEqual(vscode.window.activeNotebookEditor!.document.cells[0].outputs[0].outputs[2], newItem); + }); // }); // suite('webview', () => { diff --git a/src/vs/workbench/api/common/extHostNotebookDocument.ts b/src/vs/workbench/api/common/extHostNotebookDocument.ts index e9e715885c4..b20e4c9ed1e 100644 --- a/src/vs/workbench/api/common/extHostNotebookDocument.ts +++ b/src/vs/workbench/api/common/extHostNotebookDocument.ts @@ -13,7 +13,7 @@ import { CellKind, INotebookDocumentPropertiesChangeData } from 'vs/workbench/ap import { ExtHostDocumentsAndEditors, IExtHostModelAddedData } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters'; import * as extHostTypes from 'vs/workbench/api/common/extHostTypes'; -import { IMainCellDto, IOutputDto, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { IMainCellDto, IOutputDto, IOutputItemDto, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import * as vscode from 'vscode'; class RawContentChangeEvent { @@ -100,6 +100,17 @@ export class ExtHostCell { this._outputs = newOutputs; } + setOutputItems(outputId: string, append: boolean, newOutputItems: IOutputItemDto[]) { + const output = this._outputs.find(op => op.outputId === outputId); + if (output) { + if (append) { + output.outputs = [...output.outputs, ...newOutputItems]; + } else { + output.outputs = newOutputItems; + } + } + } + setMetadata(newMetadata: NotebookCellMetadata): void { this._metadata = extHostTypeConverters.NotebookCellMetadata.to(newMetadata); } @@ -211,6 +222,8 @@ export class ExtHostNotebookDocument extends Disposable { this._moveCell(e.index, e.newIdx); } else if (e.kind === NotebookCellsChangeType.Output) { this._setCellOutputs(e.index, e.outputs); + } else if (e.kind === NotebookCellsChangeType.OutputItem) { + this._setCellOutputItems(e.index, e.outputId, e.append, e.outputItems); } else if (e.kind === NotebookCellsChangeType.ChangeLanguage) { this._changeCellLanguage(e.index, e.language); } else if (e.kind === NotebookCellsChangeType.ChangeCellMetadata) { @@ -301,6 +314,12 @@ export class ExtHostNotebookDocument extends Disposable { this._emitter.emitCellOutputsChange({ document: this.notebookDocument, cells: [cell.cell] }); } + private _setCellOutputItems(index: number, outputId: string, append: boolean, outputItems: IOutputItemDto[]): void { + const cell = this._cells[index]; + cell.setOutputItems(outputId, append, outputItems); + this._emitter.emitCellOutputsChange({ document: this.notebookDocument, cells: [cell.cell] }); + } + private _changeCellLanguage(index: number, language: string): void { const cell = this._cells[index]; const event: vscode.NotebookCellLanguageChangeEvent = { document: this.notebookDocument, cell: cell.cell, language }; diff --git a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts index 3885b5e3d02..5d5364651e5 100644 --- a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts +++ b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts @@ -661,6 +661,14 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel const output = cell.outputs[outputIndex]; output.appendData(items); + this._eventEmitter.emit({ + kind: NotebookCellsChangeType.OutputItem, + index: this._cells.indexOf(cell), + outputId: output.outputId, + outputItems: items, + append: true, + transient: this.transientOptions.transientOutputs + }, true); } private _replaceNotebookCellOutputItems(cellHandle: number, outputId: string, items: IOutputItemDto[]) { @@ -677,6 +685,14 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel const output = cell.outputs[outputIndex]; output.replaceData(items); + this._eventEmitter.emit({ + kind: NotebookCellsChangeType.OutputItem, + index: this._cells.indexOf(cell), + outputId: output.outputId, + outputItems: items, + append: false, + transient: this.transientOptions.transientOutputs + }, true); } private _moveCellToIdx(index: number, length: number, newIdx: number, synchronous: boolean, pushedToUndoStack: boolean, beforeSelections: number[] | undefined, endSelections: number[] | undefined): boolean { diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index dee355a50bb..be7d26f468d 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -237,9 +237,10 @@ export enum NotebookCellsChangeType { Initialize = 6, ChangeCellMetadata = 7, Output = 8, - ChangeCellContent = 9, - ChangeDocumentMetadata = 10, - Unknown = 11 + OutputItem = 9, + ChangeCellContent = 10, + ChangeDocumentMetadata = 11, + Unknown = 12 } export interface NotebookCellsInitializeEvent { @@ -270,6 +271,14 @@ export interface NotebookOutputChangedEvent { readonly outputs: IOutputDto[]; } +export interface NotebookOutputItemChangedEvent { + readonly kind: NotebookCellsChangeType.OutputItem; + readonly index: number; + readonly outputId: string; + readonly outputItems: IOutputItemDto[]; + readonly append: boolean; +} + export interface NotebookCellsChangeLanguageEvent { readonly kind: NotebookCellsChangeType.ChangeLanguage; readonly index: number; @@ -291,14 +300,14 @@ export interface NotebookDocumentUnknownChangeEvent { readonly kind: NotebookCellsChangeType.Unknown; } -export type NotebookRawContentEventDto = NotebookCellsInitializeEvent | NotebookDocumentChangeMetadataEvent | NotebookCellContentChangeEvent | NotebookCellsModelChangedEvent | NotebookCellsModelMoveEvent | NotebookOutputChangedEvent | NotebookCellsChangeLanguageEvent | NotebookCellsChangeMetadataEvent | NotebookDocumentUnknownChangeEvent; +export type NotebookRawContentEventDto = NotebookCellsInitializeEvent | NotebookDocumentChangeMetadataEvent | NotebookCellContentChangeEvent | NotebookCellsModelChangedEvent | NotebookCellsModelMoveEvent | NotebookOutputChangedEvent | NotebookOutputItemChangedEvent | NotebookCellsChangeLanguageEvent | NotebookCellsChangeMetadataEvent | NotebookDocumentUnknownChangeEvent; export type NotebookCellsChangedEventDto = { readonly rawEvents: NotebookRawContentEventDto[]; readonly versionId: number; }; -export type NotebookRawContentEvent = (NotebookCellsInitializeEvent | NotebookDocumentChangeMetadataEvent | NotebookCellContentChangeEvent | NotebookCellsModelChangedEvent | NotebookCellsModelMoveEvent | NotebookOutputChangedEvent | NotebookCellsChangeLanguageEvent | NotebookCellsChangeMetadataEvent | NotebookDocumentUnknownChangeEvent) & { transient: boolean; }; +export type NotebookRawContentEvent = (NotebookCellsInitializeEvent | NotebookDocumentChangeMetadataEvent | NotebookCellContentChangeEvent | NotebookCellsModelChangedEvent | NotebookCellsModelMoveEvent | NotebookOutputChangedEvent | NotebookOutputItemChangedEvent | NotebookCellsChangeLanguageEvent | NotebookCellsChangeMetadataEvent | NotebookDocumentUnknownChangeEvent) & { transient: boolean; }; export type NotebookTextModelChangedEvent = { readonly rawEvents: NotebookRawContentEvent[]; readonly versionId: number; From da1439d5dbae09d6dd88fd2fb914f4f7c31aa111 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 16 Feb 2021 14:19:02 -0800 Subject: [PATCH 228/325] testing: tweak autorun icon checked state --- .../contrib/testing/browser/media/testing.css | 16 ++++++++++++++-- .../workbench/contrib/testing/browser/theme.ts | 9 ++++++--- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/testing/browser/media/testing.css b/src/vs/workbench/contrib/testing/browser/media/testing.css index 19896bdbd8d..5e3adce155b 100644 --- a/src/vs/workbench/contrib/testing/browser/media/testing.css +++ b/src/vs/workbench/contrib/testing/browser/media/testing.css @@ -60,8 +60,20 @@ margin-right: 8px; } -.monaco-workbench .part > .title > .title-actions .action-label.codicon-testing-autorun::before { - padding: 2px; +.monaco-workbench .part > .title > .title-actions .action-label.codicon-testing-autorun::after { + content: ''; + display: none; + position: absolute; + width: 0.4em; + height: 0.4em; + top: 50%; + left: 50%; + margin: 0.1em 0 0 0.05em; + border-radius: 100%; +} + +.monaco-workbench .part > .title > .title-actions .action-label.codicon-testing-autorun.checked::after { + display: block; } .codicon-testing-loading-icon::before { diff --git a/src/vs/workbench/contrib/testing/browser/theme.ts b/src/vs/workbench/contrib/testing/browser/theme.ts index 3c80d02eae0..635baca1d34 100644 --- a/src/vs/workbench/contrib/testing/browser/theme.ts +++ b/src/vs/workbench/contrib/testing/browser/theme.ts @@ -8,6 +8,7 @@ import { localize } from 'vs/nls'; import { editorErrorForeground, editorForeground, editorHintForeground, editorInfoForeground, editorWarningForeground, inputActiveOptionBackground, inputActiveOptionBorder, inputActiveOptionForeground, registerColor } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { TestMessageSeverity, TestRunState } from 'vs/workbench/api/common/extHostTypes'; +import { ACTIVITY_BAR_BADGE_BACKGROUND } from 'vs/workbench/common/theme'; export const testingColorIconFailed = registerColor('testing.iconFailed', { dark: '#f14c4c', @@ -135,15 +136,17 @@ registerThemingParticipant((theme, collector) => { //#region active buttons const inputActiveOptionBorderColor = theme.getColor(inputActiveOptionBorder); if (inputActiveOptionBorderColor) { - collector.addRule(`.testing-filter-button.checked, .codicon-testing-autorun.checked::before { border-color: ${inputActiveOptionBorderColor}; }`); + collector.addRule(`.testing-filter-button.checked { border-color: ${inputActiveOptionBorderColor}; }`); } const inputActiveOptionForegroundColor = theme.getColor(inputActiveOptionForeground); if (inputActiveOptionForegroundColor) { - collector.addRule(`.testing-filter-button.checked, .codicon-testing-autorun.checked::before { color: ${inputActiveOptionForegroundColor}; }`); + collector.addRule(`.testing-filter-button.checked { color: ${inputActiveOptionForegroundColor}; }`); } const inputActiveOptionBackgroundColor = theme.getColor(inputActiveOptionBackground); if (inputActiveOptionBackgroundColor) { - collector.addRule(`.testing-filter-button.checked, .codicon-testing-autorun.checked::before { background-color: ${inputActiveOptionBackgroundColor}; }`); + collector.addRule(`.testing-filter-button.checked { background-color: ${inputActiveOptionBackgroundColor}; }`); } + const badgeColor = theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND); + collector.addRule(`.monaco-workbench .part > .title > .title-actions .action-label.codicon-testing-autorun::after { background-color: ${badgeColor}; }`); //#endregion }); From b050d09527bc80fc8b9f5e35f860b69c92d06a49 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 16 Feb 2021 14:39:27 -0800 Subject: [PATCH 229/325] testing: filter focus on view visible Fixes #114991 --- .../contrib/testing/browser/testingExplorerView.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts index aa396f4e514..0b43ef1509d 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts @@ -280,6 +280,12 @@ export class TestingExplorerViewModel extends Disposable { } })); + this._register(onDidChangeVisibility(visible => { + if (visible) { + filterState.focusInput(); + } + })); + this.updatePreferredProjection(); this.onDidChangeSelection = this.tree.onDidChangeSelection; From 3d19580d17ab9251f75c296645733208089fd0c8 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 16 Feb 2021 15:08:40 -0800 Subject: [PATCH 230/325] fix: hide debug/run actions if no tests are applicable Fixes #115017 --- .../testing/browser/testExplorerActions.ts | 10 ++++--- .../contrib/testing/common/testServiceImpl.ts | 27 ++++++++++++++++--- .../testing/common/testingContextKeys.ts | 2 ++ 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts index 52f558c3f00..62310f4dea3 100644 --- a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts +++ b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts @@ -197,7 +197,10 @@ abstract class RunOrDebugAllAllAction extends Action2 { group: 'navigation', when: ContextKeyAndExpr.create([ ContextKeyEqualsExpr.create('view', Testing.ExplorerViewId), - ContextKeyEqualsExpr.create(TestingContextKeys.isRunning.serialize(), false), + TestingContextKeys.isRunning.isEqualTo(false), + debug + ? TestingContextKeys.hasDebuggableTests.isEqualTo(true) + : TestingContextKeys.hasRunnableTests.isEqualTo(true), ]) } }); @@ -518,7 +521,6 @@ abstract class RunOrDebugAtCursor extends Action2 { return; } - const testService = accessor.get(ITestService); const collection = testService.subscribeToDiffs(ExtHostTestingResource.TextDocument, model.uri); @@ -694,7 +696,9 @@ abstract class RunOrDebugTestResults extends Action2 { } } - await this.runTest(testService, toRun); + if (toRun.length) { + await this.runTest(testService, toRun); + } } finally { workspaceTests.dispose(); } diff --git a/src/vs/workbench/contrib/testing/common/testServiceImpl.ts b/src/vs/workbench/contrib/testing/common/testServiceImpl.ts index 95d4a9e7bc8..8b65c2c83ff 100644 --- a/src/vs/workbench/contrib/testing/common/testServiceImpl.ts +++ b/src/vs/workbench/contrib/testing/common/testServiceImpl.ts @@ -39,12 +39,16 @@ export class TestService extends Disposable implements ITestService { private readonly busyStateChangeEmitter = new Emitter(); private readonly changeProvidersEmitter = new Emitter<{ delta: number }>(); private readonly providerCount: IContextKey; + private readonly hasRunnable: IContextKey; + private readonly hasDebuggable: IContextKey; private readonly runningTests = new Map(); private rootProviderCount = 0; constructor(@IContextKeyService contextKeyService: IContextKeyService, @INotificationService private readonly notificationService: INotificationService, @ITestResultService private readonly testResults: ITestResultService) { super(); this.providerCount = TestingContextKeys.providerCount.bindTo(contextKeyService); + this.hasDebuggable = TestingContextKeys.hasDebuggableTests.bindTo(contextKeyService); + this.hasRunnable = TestingContextKeys.hasRunnableTests.bindTo(contextKeyService); } /** @@ -216,11 +220,14 @@ export class TestService extends Disposable implements ITestService { */ public publishDiff(resource: ExtHostTestingResource, uri: UriComponents, diff: TestsDiff) { const sub = this.testSubscriptions.get(getTestSubscriptionKey(resource, URI.revive(uri))); - if (sub) { - sub.collection.apply(diff); - // console.log('accept', sub.collection, diff); - sub.onDiff.fire(diff); + if (!sub) { + return; } + + sub.collection.apply(diff); + sub.onDiff.fire(diff); + this.hasDebuggable.set(!!this.findTest(t => t.item.debuggable)); + this.hasRunnable.set(!!this.findTest(t => t.item.runnable)); } /** @@ -240,6 +247,18 @@ export class TestService extends Disposable implements ITestService { this.providerCount.set(this.testControllers.size); this.changeProvidersEmitter.fire({ delta: -1 }); } + + private findTest(predicate: (t: InternalTestItem) => boolean): InternalTestItem | undefined { + for (const { collection } of this.testSubscriptions.values()) { + for (const test of collection.all) { + if (predicate(test)) { + return test; + } + } + } + + return undefined; + } } export class MainThreadTestCollection extends AbstractIncrementalTestCollection implements IMainThreadTestCollection { diff --git a/src/vs/workbench/contrib/testing/common/testingContextKeys.ts b/src/vs/workbench/contrib/testing/common/testingContextKeys.ts index 3a1f40ad723..6f951ef63ac 100644 --- a/src/vs/workbench/contrib/testing/common/testingContextKeys.ts +++ b/src/vs/workbench/contrib/testing/common/testingContextKeys.ts @@ -9,6 +9,8 @@ import { TestExplorerViewMode, TestExplorerViewSorting } from 'vs/workbench/cont export namespace TestingContextKeys { export const providerCount = new RawContextKey('testing.providerCount', 0); + export const hasDebuggableTests = new RawContextKey('testing.hasDebuggableTests', false); + export const hasRunnableTests = new RawContextKey('testing.hasRunnableTests', false); export const viewMode = new RawContextKey('testing.explorerViewMode', TestExplorerViewMode.List); export const viewSorting = new RawContextKey('testing.explorerViewSorting', TestExplorerViewSorting.ByLocation); export const isRunning = new RawContextKey('testing.isRunning', false); From 69393e9a2faecae9579d13f7ce4e0f094973b8a5 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 16 Feb 2021 15:45:26 -0800 Subject: [PATCH 231/325] testing: improve labeling in peek for accessibility --- src/vs/monaco.d.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 4aa4fc84b84..5b0421be3f5 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -4080,12 +4080,12 @@ declare namespace monaco.editor { accessibilitySupport: IEditorOption; accessibilityPageSize: IEditorOption; ariaLabel: IEditorOption; - autoClosingBrackets: IEditorOption; - autoClosingOvertype: IEditorOption; - autoClosingQuotes: IEditorOption; + autoClosingBrackets: IEditorOption; + autoClosingOvertype: IEditorOption; + autoClosingQuotes: IEditorOption; autoIndent: IEditorOption; automaticLayout: IEditorOption; - autoSurround: IEditorOption; + autoSurround: IEditorOption; stickyTabStops: IEditorOption; codeLens: IEditorOption; codeLensFontFamily: IEditorOption; From 269cf7a98c1ac8c606be63664c756fa45e752ecc Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 16 Feb 2021 15:45:26 -0800 Subject: [PATCH 232/325] testing: improve labeling in peek for accessibility --- src/vs/editor/browser/widget/diffEditorWidget.ts | 7 +++++++ src/vs/editor/common/config/editorOptions.ts | 8 ++++++++ src/vs/monaco.d.ts | 8 ++++++++ .../contrib/testing/browser/testingOutputPeek.ts | 4 ++++ 4 files changed, 27 insertions(+) diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index c67cb67e60c..6256e77b6ec 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -1151,6 +1151,9 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE } else { result.wordWrapOverride1 = this._diffWordWrap; } + if (options.originalAriaLabel) { + result.ariaLabel = options.originalAriaLabel; + } result.readOnly = !this._originalIsEditable; result.extraEditorClassName = 'original-in-monaco-diff-editor'; return { @@ -1164,6 +1167,10 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE private _adjustOptionsForRightHandSide(options: Readonly): editorBrowser.IEditorConstructionOptions { const result = this._adjustOptionsForSubEditor(options); + if (options.modifiedAriaLabel) { + result.ariaLabel = options.modifiedAriaLabel; + } + result.wordWrapOverride1 = this._diffWordWrap; result.revealHorizontalRightPadding = EditorOptions.revealHorizontalRightPadding.defaultValue + DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH; result.scrollbar!.verticalHasArrows = false; diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index bce85536162..fd183e4fd8c 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -690,6 +690,14 @@ export interface IDiffEditorOptions extends IEditorOptions { * Control the wrapping of the diff editor. */ diffWordWrap?: 'off' | 'on' | 'inherit'; + /** + * Aria label for original editor. + */ + originalAriaLabel?: string; + /** + * Aria label for modifed editor. + */ + modifiedAriaLabel?: string; } //#endregion diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 5b0421be3f5..c8b2e0aec53 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -3247,6 +3247,14 @@ declare namespace monaco.editor { * Control the wrapping of the diff editor. */ diffWordWrap?: 'off' | 'on' | 'inherit'; + /** + * Aria label for original editor. + */ + originalAriaLabel?: string; + /** + * Aria label for modifed editor. + */ + modifiedAriaLabel?: string; } /** diff --git a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts index 3ee275e166a..3e3bb38e45a 100644 --- a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts +++ b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as dom from 'vs/base/browser/dom'; +import { alert } from 'vs/base/browser/ui/aria/aria'; import { Codicon } from 'vs/base/common/codicons'; import { Color } from 'vs/base/common/color'; import { KeyCode } from 'vs/base/common/keyCodes'; @@ -203,6 +204,7 @@ export class TestingOutputPeekController extends Disposable implements IEditorCo this.peek.value!.create(); } + alert(message.message.toString()); this.peek.value!.setModel(dto); } @@ -321,6 +323,8 @@ const diffEditorOptions: IDiffEditorOptions = { renderOverviewRuler: false, ignoreTrimWhitespace: false, renderSideBySide: true, + originalAriaLabel: localize('testingOutputExpected', 'Expected result'), + modifiedAriaLabel: localize('testingOutputActual', 'Actual result'), }; class TestingDiffOutputPeek extends TestingOutputPeek { From dfee0857c2312cc299227730817307b7e7d74267 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 16 Feb 2021 16:16:31 -0800 Subject: [PATCH 233/325] testing: run test on enter press Ref https://github.com/microsoft/vscode/issues/114653 --- .../testing/browser/testingExplorerView.ts | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts index 0b43ef1509d..c65800ac901 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as dom from 'vs/base/browser/dom'; +import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import * as aria from 'vs/base/browser/ui/aria/aria'; import { IIdentityProvider, IKeyboardNavigationLabelProvider, IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; @@ -19,7 +20,9 @@ import { Event } from 'vs/base/common/event'; import { FuzzyScore } from 'vs/base/common/filters'; import { splitGlobAware } from 'vs/base/common/glob'; import { Iterable } from 'vs/base/common/iterator'; +import { KeyCode } from 'vs/base/common/keyCodes'; import { Disposable, DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { isDefined } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import 'vs/css!./media/testing'; import { ICodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -223,6 +226,7 @@ export class TestingExplorerViewModel extends Disposable { listContainer: HTMLElement, onDidChangeVisibility: Event, private listener: TestSubscriptionListener | undefined, + @ITestService private readonly testService: ITestService, @ITestExplorerFilterState filterState: TestExplorerFilterState, @IInstantiationService private readonly instantiationService: IInstantiationService, @IEditorService private readonly editorService: IEditorService, @@ -274,7 +278,9 @@ export class TestingExplorerViewModel extends Disposable { this._register(this.tree); this._register(dom.addStandardDisposableListener(this.tree.getHTMLElement(), 'keydown', evt => { - if (DefaultKeyboardNavigationDelegate.mightProducePrintableCharacter(evt)) { + if (evt.equals(KeyCode.Enter)) { + this.handleExecuteKeypress(evt); + } else if (DefaultKeyboardNavigationDelegate.mightProducePrintableCharacter(evt)) { filterState.text.value = evt.browserEvent.key; filterState.focusInput(); } @@ -401,6 +407,27 @@ export class TestingExplorerViewModel extends Disposable { : false; } + private handleExecuteKeypress(evt: IKeyboardEvent) { + const focused = this.tree.getFocus(); + const selected = this.tree.getSelection(); + let targeted: (ITestTreeElement | null)[]; + if (focused.length === 1 && selected.includes(focused[0])) { + evt.browserEvent?.preventDefault(); + targeted = selected; + } else { + targeted = focused; + } + + const toRun = targeted + .map(e => e?.test) + .filter(isDefined) + .filter(e => e.item.runnable); + + if (toRun.length) { + this.testService.runTests({ debug: false, tests: toRun.map(t => ({ providerId: t.providerId, testId: t.id })) }); + } + } + private updatePreferredProjection() { this.projection?.dispose(); if (!this.listener) { From 90c5ceafc38c90b94f615efc67fa3f3a4a884d2e Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 16 Feb 2021 16:38:30 -0800 Subject: [PATCH 234/325] monaco: fix conflicted file --- src/vs/monaco.d.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index c8b2e0aec53..7b729f29901 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -4088,12 +4088,12 @@ declare namespace monaco.editor { accessibilitySupport: IEditorOption; accessibilityPageSize: IEditorOption; ariaLabel: IEditorOption; - autoClosingBrackets: IEditorOption; - autoClosingOvertype: IEditorOption; - autoClosingQuotes: IEditorOption; + autoClosingBrackets: IEditorOption; + autoClosingOvertype: IEditorOption; + autoClosingQuotes: IEditorOption; autoIndent: IEditorOption; automaticLayout: IEditorOption; - autoSurround: IEditorOption; + autoSurround: IEditorOption; stickyTabStops: IEditorOption; codeLens: IEditorOption; codeLensFontFamily: IEditorOption; From b0bd28137a6c5f9b3a557213e6b32d5f6cc43b1c Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 16 Feb 2021 16:02:39 -0800 Subject: [PATCH 235/325] add test for #115855. --- .../src/singlefolder-tests/notebook.test.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts index 80b241e0322..acc936a56b7 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts @@ -1488,6 +1488,29 @@ suite('Notebook API tests', function () { assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells[0].outputs[0].outputs.length, 3); assert.deepStrictEqual(vscode.window.activeNotebookEditor!.document.cells[0].outputs[0].outputs[2], newItem); }); + + test('#115855 onDidSaveNotebookDocument', async function () { + assertInitalState(); + const resource = await createRandomFile('', undefined, '.vsctestnb'); + await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); + + const cellsChangeEvent = asPromise(vscode.notebook.onDidChangeNotebookCells); + await vscode.window.activeNotebookEditor!.edit(editBuilder => { + editBuilder.replaceCells(1, 0, [{ cellKind: vscode.NotebookCellKind.Code, language: 'javascript', source: 'test 2', outputs: [], metadata: undefined }]); + }); + + const cellChangeEventRet = await cellsChangeEvent; + assert.strictEqual(cellChangeEventRet.document === vscode.window.activeNotebookEditor?.document, true); + assert.strictEqual(cellChangeEventRet.document.isDirty, true); + + await withEvent(vscode.notebook.onDidSaveNotebookDocument, async event => { + await vscode.commands.executeCommand('workbench.action.files.saveAll'); + await event; + assert.strictEqual(cellChangeEventRet.document.isDirty, false); + }); + await saveAllFilesAndCloseAll(resource); + }); + // }); // suite('webview', () => { From b3f8737839d406381b66a0397fe488bb7866cc53 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 16 Feb 2021 16:40:26 -0800 Subject: [PATCH 236/325] fix #116808. --- .../src/singlefolder-tests/notebook.test.ts | 17 ++++++++++++++++- .../workbench/api/browser/mainThreadNotebook.ts | 1 + src/vs/workbench/api/common/extHostNotebook.ts | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts index acc936a56b7..004b53a635a 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts @@ -1403,7 +1403,7 @@ suite('Notebook API tests', function () { assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.document.getText(), 'var abc = 0;'); // no kernel -> no default language - assert.strictEqual(vscode.window.activeNotebookEditor!.kernel, undefined); + // assert.strictEqual(vscode.window.activeNotebookEditor!.kernel, undefined); assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.language, 'typescript'); await vscode.commands.executeCommand('vscode.openWith', resource, 'default'); @@ -1511,6 +1511,21 @@ suite('Notebook API tests', function () { await saveAllFilesAndCloseAll(resource); }); + + test('#116808, active kernel should not be undefined', async function () { + assertInitalState(); + const resource = await createRandomFile('', undefined, '.vsctestnb'); + await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); + + await withEvent(vscode.notebook.onDidChangeActiveNotebookKernel, async event => { + await event; + assert.notStrictEqual(vscode.window.activeNotebookEditor?.kernel, undefined); + assert.strictEqual(vscode.window.activeNotebookEditor?.kernel?.id, 'mainKernel'); + }); + + await saveAllFilesAndCloseAll(resource); + }); + // }); // suite('webview', () => { diff --git a/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts index b9ba768326d..f761a9fec14 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -556,6 +556,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo const result: INotebookKernel[] = []; const kernelsDto = await that._proxy.$provideNotebookKernels(handle, uri, token); for (const dto of kernelsDto) { + console.log('kerneldto', dto.providerHandle); result.push({ id: dto.id, diff --git a/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts index b58b4880b57..04a5cd56a2c 100644 --- a/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -123,6 +123,7 @@ export class ExtHostNotebookKernelProviderAdapter extends Disposable { label: kernel.label, extension: this._extension.identifier, extensionLocation: this._extension.extensionLocation, + providerHandle: this._handle, description: kernel.description, detail: kernel.detail, isPreferred: kernel.isPreferred, From 79b8259abb8fd077fe2431e4e773b62cf7e55c7e Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 16 Feb 2021 19:41:30 -0800 Subject: [PATCH 237/325] change cell language with cell change events. --- .../src/singlefolder-tests/notebook.test.ts | 28 ++++- .../notebook/browser/contrib/coreActions.ts | 102 ++++++++++++++---- 2 files changed, 110 insertions(+), 20 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts index 004b53a635a..81a03ed3250 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts @@ -135,7 +135,7 @@ suite('Notebook API tests', function () { id: 'mainKernel', label: 'Notebook Test Kernel', isPreferred: true, - supportedLanguages: ['typescript'], + supportedLanguages: ['typescript', 'javascript'], executeAllCells: async (_document: vscode.NotebookDocument) => { const edit = new vscode.WorkspaceEdit(); @@ -174,7 +174,7 @@ suite('Notebook API tests', function () { id: 'secondaryKernel', label: 'Notebook Secondary Test Kernel', isPreferred: false, - supportedLanguages: ['typescript'], + supportedLanguages: ['typescript', 'javascript'], executeAllCells: async (_document: vscode.NotebookDocument) => { const edit = new vscode.WorkspaceEdit(); edit.replaceNotebookCellOutput(_document.uri, 0, [new vscode.NotebookCellOutput([ @@ -471,6 +471,30 @@ suite('Notebook API tests', function () { await saveFileAndCloseAll(resource); }); + test('change cell language', async function () { + assertInitalState(); + const resource = await createRandomFile('', undefined, '.vsctestnb'); + await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); + + assert.strictEqual(vscode.window.activeNotebookEditor?.document.cells[0].language, 'typescript'); + assert.strictEqual(vscode.window.activeNotebookEditor?.document.cells[0].cellKind, vscode.NotebookCellKind.Code); + await withEvent(vscode.notebook.onDidChangeCellLanguage, async event => { + await vscode.commands.executeCommand('notebook.cell.changeLanguage', { start: 0, end: 1 }, 'javascript'); + await event; + assert.strictEqual(vscode.window.activeNotebookEditor?.document.cells[0].language, 'javascript'); + }); + + // switch to markdown will change the cell kind + await withEvent(vscode.notebook.onDidChangeNotebookCells, async event => { + await vscode.commands.executeCommand('notebook.cell.changeLanguage', { start: 0, end: 1 }, 'markdown'); + await event; + assert.strictEqual(vscode.window.activeNotebookEditor?.document.cells[0].language, 'markdown'); + assert.strictEqual(vscode.window.activeNotebookEditor?.document.cells[0].cellKind, vscode.NotebookCellKind.Markdown); + }); + + await saveAllFilesAndCloseAll(resource); + }); + test('edit API (replaceCells)', async function () { assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts index 26772735238..56f85535ae3 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts @@ -1607,19 +1607,81 @@ interface ILanguagePickInput extends IQuickPickItem { description: string; } -export class ChangeCellLanguageAction extends NotebookCellAction { + +interface IChangeCellContext extends INotebookCellActionContext { + // TODO@rebornix : `cells` + // range: ICellRange; + language?: string; +} + +export class ChangeCellLanguageAction extends NotebookCellAction { constructor() { super({ id: CHANGE_CELL_LANGUAGE, title: localize('changeLanguage', 'Change Cell Language'), + description: { + description: localize('changeLanguage', 'Change Cell Language'), + args: [ + { + name: 'range', + description: 'The cell range', + schema: { + 'type': 'object', + 'required': ['start', 'end'], + 'properties': { + 'start': { + 'type': 'number' + }, + 'end': { + 'type': 'number' + } + } + } + }, + { + name: 'language', + description: 'The target cell language', + schema: { + 'type': 'string' + } + } + ] + } }); } - async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise { - this.showLanguagePicker(accessor, context); + protected getCellContextFromArgs(accessor: ServicesAccessor, context?: ICellRange, ...additionalArgs: any[]): IChangeCellContext | undefined { + if (!context || typeof context.start !== 'number' || typeof context.end !== 'number' || context.start >= context.end) { + return; + } + + const language = additionalArgs.length && typeof additionalArgs[0] === 'string' ? additionalArgs[0] : undefined; + const activeEditorContext = this.getEditorContextFromArgsOrActive(accessor); + + if (!activeEditorContext || !activeEditorContext.notebookEditor.viewModel || context.start >= activeEditorContext.notebookEditor.viewModel.viewCells.length) { + return; + } + + const cells = activeEditorContext.notebookEditor.viewModel.viewCells; + + // TODO@rebornix, support multiple cells + return { + notebookEditor: activeEditorContext.notebookEditor, + cell: cells[context.start], + language + }; } - private async showLanguagePicker(accessor: ServicesAccessor, context: INotebookCellActionContext) { + + async runWithContext(accessor: ServicesAccessor, context: IChangeCellContext): Promise { + if (context.language) { + await this.setLanguage(context, context.language); + } else { + await this.showLanguagePicker(accessor, context); + } + } + + private async showLanguagePicker(accessor: ServicesAccessor, context: IChangeCellContext) { const topItems: ILanguagePickInput[] = []; const mainItems: ILanguagePickInput[] = []; @@ -1671,21 +1733,25 @@ export class ChangeCellLanguageAction extends NotebookCellAction { const selection = await quickInputService.pick(picks, { placeHolder: localize('pickLanguageToConfigure', "Select Language Mode") }) as ILanguagePickInput | undefined; if (selection && selection.languageId) { - if (selection.languageId === 'markdown' && context.cell?.language !== 'markdown') { - const newCell = await changeCellToKind(CellKind.Markdown, { cell: context.cell, notebookEditor: context.notebookEditor }, 'markdown'); - if (newCell) { - context.notebookEditor.focusNotebookCell(newCell, 'editor'); - } - } else if (selection.languageId !== 'markdown' && context.cell?.cellKind === CellKind.Markdown) { - await changeCellToKind(CellKind.Code, { cell: context.cell, notebookEditor: context.notebookEditor }, selection.languageId); - } else { - const index = context.notebookEditor.viewModel.notebookDocument.cells.indexOf(context.cell.model); - context.notebookEditor.viewModel.notebookDocument.applyEdits( - context.notebookEditor.viewModel.notebookDocument.versionId, - [{ editType: CellEditType.CellLanguage, index, language: selection.languageId }], - true, undefined, () => undefined, undefined - ); + await this.setLanguage(context, selection.languageId); + } + } + + private async setLanguage(context: IChangeCellContext, languageId: string) { + if (languageId === 'markdown' && context.cell?.language !== 'markdown') { + const newCell = await changeCellToKind(CellKind.Markdown, { cell: context.cell, notebookEditor: context.notebookEditor }, 'markdown'); + if (newCell) { + context.notebookEditor.focusNotebookCell(newCell, 'editor'); } + } else if (languageId !== 'markdown' && context.cell?.cellKind === CellKind.Markdown) { + await changeCellToKind(CellKind.Code, { cell: context.cell, notebookEditor: context.notebookEditor }, languageId); + } else { + const index = context.notebookEditor.viewModel.notebookDocument.cells.indexOf(context.cell.model); + context.notebookEditor.viewModel.notebookDocument.applyEdits( + context.notebookEditor.viewModel.notebookDocument.versionId, + [{ editType: CellEditType.CellLanguage, index, language: languageId }], + true, undefined, () => undefined, undefined + ); } } From c03c75876517713fc02717dd85892b7b2199e0a4 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 16 Feb 2021 20:40:18 -0800 Subject: [PATCH 238/325] Select the first search row when initially focusing it from the search inputs, now that the coloring is easier to differentiate --- src/vs/workbench/contrib/search/browser/searchView.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index 8350e27ee2d..027b9fcd189 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -1102,7 +1102,7 @@ export class SearchView extends ViewPane { this.tree.domFocus(); const selection = this.tree.getSelection(); if (selection.length === 0) { - this.tree.focusNext(); + this.tree.focusNext(undefined, undefined, getSelectionKeyboardEvent()); } } } From 90f5ef65a09c975315cfff7022cb37f5e75ab539 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 16 Feb 2021 21:07:55 -0800 Subject: [PATCH 239/325] Delete notebookTestMain --- extensions/vscode-notebook-tests/package.json | 2 +- .../src/{notebookSmokeTestMain.ts => extension.ts} | 2 +- .../vscode-notebook-tests/src/notebookTestMain.ts | 14 -------------- 3 files changed, 2 insertions(+), 16 deletions(-) rename extensions/vscode-notebook-tests/src/{notebookSmokeTestMain.ts => extension.ts} (98%) delete mode 100644 extensions/vscode-notebook-tests/src/notebookTestMain.ts diff --git a/extensions/vscode-notebook-tests/package.json b/extensions/vscode-notebook-tests/package.json index 153ce130e24..78164843df9 100644 --- a/extensions/vscode-notebook-tests/package.json +++ b/extensions/vscode-notebook-tests/package.json @@ -8,7 +8,7 @@ "activationEvents": [ "*" ], - "main": "./out/notebookTestMain", + "main": "./out/extension", "enableProposedApi": true, "engines": { "vscode": "^1.25.0" diff --git a/extensions/vscode-notebook-tests/src/notebookSmokeTestMain.ts b/extensions/vscode-notebook-tests/src/extension.ts similarity index 98% rename from extensions/vscode-notebook-tests/src/notebookSmokeTestMain.ts rename to extensions/vscode-notebook-tests/src/extension.ts index 0e3e7426f23..bf66b529bc2 100644 --- a/extensions/vscode-notebook-tests/src/notebookSmokeTestMain.ts +++ b/extensions/vscode-notebook-tests/src/extension.ts @@ -11,7 +11,7 @@ function wait(ms: number): Promise { return new Promise(r => setTimeout(r, ms)); } -export function smokeTestActivate(context: vscode.ExtensionContext): any { +export function activate(context: vscode.ExtensionContext): any { context.subscriptions.push(vscode.commands.registerCommand('vscode-notebook-tests.createNewNotebook', async () => { const workspacePath = vscode.workspace.workspaceFolders![0].uri.fsPath; const notebookPath = path.join(workspacePath, 'test.smoke-nb'); diff --git a/extensions/vscode-notebook-tests/src/notebookTestMain.ts b/extensions/vscode-notebook-tests/src/notebookTestMain.ts deleted file mode 100644 index 8cf19b430be..00000000000 --- a/extensions/vscode-notebook-tests/src/notebookTestMain.ts +++ /dev/null @@ -1,14 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as vscode from 'vscode'; -import { smokeTestActivate } from './notebookSmokeTestMain'; - -export function activate(context: vscode.ExtensionContext): any { - smokeTestActivate(context); - - - -} From a36e9b3e092a6f989c3d88507cb3a5980c9724ce Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 17 Feb 2021 07:30:18 +0100 Subject: [PATCH 240/325] add prefix to main errors when logged into renderer --- src/vs/code/electron-main/app.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 1a378fd011f..4d17030027a 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -388,7 +388,7 @@ export class CodeApplication extends Disposable { // take only the message and stack property const friendlyError = { - message: err.message, + message: `[uncaught exception in main]: ${err.message}`, stack: err.stack }; From 45704f8f340bbd57010d5046926f5e69cbf442bd Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 17 Feb 2021 07:48:58 +0100 Subject: [PATCH 241/325] storage - lift more things up to abstract impl --- .../parts/storage/test/node/storage.test.ts | 1 + .../storage/browser/storageService.ts | 75 +++++-------------- src/vs/platform/storage/common/storage.ts | 64 +++++++++++++++- .../electron-sandbox/storageService2.ts | 44 +---------- .../platform/storage/node/storageService.ts | 45 ++--------- .../test/browser/storageService.test.ts | 4 +- .../storage/test/node/storageService.test.ts | 8 +- src/vs/workbench/browser/web.main.ts | 4 +- .../electron-browser/desktop.main.ts | 4 +- 9 files changed, 101 insertions(+), 148 deletions(-) diff --git a/src/vs/base/parts/storage/test/node/storage.test.ts b/src/vs/base/parts/storage/test/node/storage.test.ts index 46193801f71..990e531905e 100644 --- a/src/vs/base/parts/storage/test/node/storage.test.ts +++ b/src/vs/base/parts/storage/test/node/storage.test.ts @@ -104,6 +104,7 @@ flakySuite('Storage Library', function () { strictEqual(deletePromiseResolved, true); await storage.close(); + await storage.close(); // it is ok to call this multiple times }); test('external changes', async () => { diff --git a/src/vs/platform/storage/browser/storageService.ts b/src/vs/platform/storage/browser/storageService.ts index aa2eb5f6c7d..8c60c691d1f 100644 --- a/src/vs/platform/storage/browser/storageService.ts +++ b/src/vs/platform/storage/browser/storageService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { Emitter } from 'vs/base/common/event'; import { StorageScope, IS_NEW_KEY, AbstractStorageService } from 'vs/platform/storage/common/storage'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -12,11 +12,13 @@ import { IFileService, FileChangeType } from 'vs/platform/files/common/files'; import { IStorage, Storage, IStorageDatabase, IStorageItemsChangeEvent, IUpdateRequest } from 'vs/base/parts/storage/common/storage'; import { URI } from 'vs/base/common/uri'; import { joinPath } from 'vs/base/common/resources'; -import { runWhenIdle, RunOnceScheduler, Promises } from 'vs/base/common/async'; +import { Promises } from 'vs/base/common/async'; import { VSBuffer } from 'vs/base/common/buffer'; export class BrowserStorageService extends AbstractStorageService { + private static BROWSER_DEFAULT_FLUSH_INTERVAL = 5 * 1000; // every 5s because async operations are not permitted on shutdown + private globalStorage: IStorage | undefined; private workspaceStorage: IStorage | undefined; @@ -26,38 +28,26 @@ export class BrowserStorageService extends AbstractStorageService { private globalStorageFile: URI | undefined; private workspaceStorageFile: URI | undefined; - private initializePromise: Promise | undefined; - - private readonly periodicFlushScheduler = this._register(new RunOnceScheduler(() => this.doFlushWhenIdle(), 5000 /* every 5s */)); - private runWhenIdleDisposable: IDisposable | undefined = undefined; - get hasPendingUpdate(): boolean { return (!!this.globalStorageDatabase && this.globalStorageDatabase.hasPendingUpdate) || (!!this.workspaceStorageDatabase && this.workspaceStorageDatabase.hasPendingUpdate); } constructor( + private readonly payload: IWorkspaceInitializationPayload, @IEnvironmentService private readonly environmentService: IEnvironmentService, @IFileService private readonly fileService: IFileService ) { - super(); + super({ flushInterval: BrowserStorageService.BROWSER_DEFAULT_FLUSH_INTERVAL }); } - initialize(payload: IWorkspaceInitializationPayload): Promise { - if (!this.initializePromise) { - this.initializePromise = this.doInitialize(payload); - } - - return this.initializePromise; - } - - private async doInitialize(payload: IWorkspaceInitializationPayload): Promise { + protected async doInitialize(): Promise { // Ensure state folder exists const stateRoot = joinPath(this.environmentService.userRoamingDataHome, 'state'); await this.fileService.createFolder(stateRoot); // Workspace Storage - this.workspaceStorageFile = joinPath(stateRoot, `${payload.id}.json`); + this.workspaceStorageFile = joinPath(stateRoot, `${this.payload.id}.json`); this.workspaceStorageDatabase = this._register(new FileStorageDatabase(this.workspaceStorageFile, false /* do not watch for external changes */, this.fileService)); this.workspaceStorage = this._register(new Storage(this.workspaceStorageDatabase)); @@ -90,13 +80,6 @@ export class BrowserStorageService extends AbstractStorageService { } else if (firstWorkspaceOpen) { this.workspaceStorage.set(IS_NEW_KEY, false); } - - // In the browser we do not have support for long running unload sequences. As such, - // we cannot ask for saving state in that moment, because that would result in a - // long running operation. - // Instead, periodically ask customers to save save. The library will be clever enough - // to only save state that has actually changed. - this.periodicFlushScheduler.schedule(); } protected getStorage(scope: StorageScope): IStorage | undefined { @@ -111,30 +94,17 @@ export class BrowserStorageService extends AbstractStorageService { throw new Error('Migrating storage is currently unsupported in Web'); } - private doFlushWhenIdle(): void { - - // Dispose any previous idle runner - dispose(this.runWhenIdleDisposable); - - // Run when idle - this.runWhenIdleDisposable = runWhenIdle(() => { - - // this event will potentially cause new state to be stored - // since new state will only be created while the document - // has focus, one optimization is to not run this when the - // document has no focus, assuming that state has not changed - // - // another optimization is to not collect more state if we - // have a pending update already running which indicates - // that the connection is either slow or disconnected and - // thus unhealthy. - if (document.hasFocus() && !this.hasPendingUpdate) { - this.flush(); - } - - // repeat - this.periodicFlushScheduler.schedule(); - }); + protected shouldScheduleFlush(): boolean { + // this flush() will potentially cause new state to be stored + // since new state will only be created while the document + // has focus, one optimization is to not run this when the + // document has no focus, assuming that state has not changed + // + // another optimization is to not collect more state if we + // have a pending update already running which indicates + // that the connection is either slow or disconnected and + // thus unhealthy. + return document.hasFocus() && !this.hasPendingUpdate; } close(): void { @@ -148,13 +118,6 @@ export class BrowserStorageService extends AbstractStorageService { // get triggered in this phase. this.dispose(); } - - dispose(): void { - dispose(this.runWhenIdleDisposable); - this.runWhenIdleDisposable = undefined; - - super.dispose(); - } } export class FileStorageDatabase extends Disposable implements IStorageDatabase { diff --git a/src/vs/platform/storage/common/storage.ts b/src/vs/platform/storage/common/storage.ts index aad6f035908..ce08361d389 100644 --- a/src/vs/platform/storage/common/storage.ts +++ b/src/vs/platform/storage/common/storage.ts @@ -5,11 +5,11 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Event, Emitter, PauseableEmitter } from 'vs/base/common/event'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, dispose, MutableDisposable } from 'vs/base/common/lifecycle'; import { isUndefinedOrNull } from 'vs/base/common/types'; import { IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces'; import { InMemoryStorageDatabase, IStorage, Storage } from 'vs/base/parts/storage/common/storage'; -import { Promises } from 'vs/base/common/async'; +import { Promises, RunOnceScheduler, runWhenIdle } from 'vs/base/common/async'; export const IS_NEW_KEY = '__$__isNewStorageMarker'; const TARGET_KEY = '__$__targetStorageMarker'; @@ -220,10 +220,16 @@ interface IKeyTargets { [key: string]: StorageTarget } +export interface IStorageServiceOptions { + flushInterval: number; +} + export abstract class AbstractStorageService extends Disposable implements IStorageService { declare readonly _serviceBrand: undefined; + private static DEFAULT_FLUSH_INTERVAL = 60 * 1000; // every minute + private readonly _onDidChangeValue = this._register(new PauseableEmitter()); readonly onDidChangeValue = this._onDidChangeValue.event; @@ -233,6 +239,56 @@ export abstract class AbstractStorageService extends Disposable implements IStor private readonly _onWillSaveState = this._register(new Emitter()); readonly onWillSaveState = this._onWillSaveState.event; + private initializationPromise: Promise | undefined; + + private readonly flushScheduler = this._register(new RunOnceScheduler(() => this.doFlushWhenIdle(), this.options.flushInterval)); + private readonly runFlushWhenIdle = this._register(new MutableDisposable()); + + constructor(private options: IStorageServiceOptions = { flushInterval: AbstractStorageService.DEFAULT_FLUSH_INTERVAL }) { + super(); + } + + private doFlushWhenIdle(): void { + this.runFlushWhenIdle.value = runWhenIdle(() => { + if (this.shouldScheduleFlush()) { + this.flush(); + } + + // repeat + this.flushScheduler.schedule(); + }); + } + + protected shouldScheduleFlush(): boolean { + return true; + } + + protected stopFlushScheduler(): void { + dispose([this.runFlushWhenIdle, this.flushScheduler]); + } + + initialize(): Promise { + if (!this.initializationPromise) { + this.initializationPromise = (async () => { + + // Ask subclasses to initialize storage + await this.doInitialize(); + + // On some OS we do not get enough time to persist state on shutdown (e.g. when + // Windows restarts after applying updates). In other cases, VSCode might crash, + // so we periodically save state to reduce the chance of loosing any state. + // In the browser we do not have support for long running unload sequences. As such, + // we cannot ask for saving state in that moment, because that would result in a + // long running operation. + // Instead, periodically ask customers to save save. The library will be clever enough + // to only save state that has actually changed. + this.flushScheduler.schedule(); + })(); + } + + return this.initializationPromise; + } + protected emitDidChangeValue(scope: StorageScope, key: string): void { // Specially handle `TARGET_KEY` @@ -424,6 +480,8 @@ export abstract class AbstractStorageService extends Disposable implements IStor // --- abstract + protected abstract doInitialize(): Promise; + protected abstract getStorage(scope: StorageScope): IStorage | undefined; protected abstract getLogDetails(scope: StorageScope): string | undefined; @@ -451,6 +509,8 @@ export class InMemoryStorageService extends AbstractStorageService { return scope === StorageScope.GLOBAL ? 'inMemory (global)' : 'inMemory (workspace)'; } + protected async doInitialize(): Promise { } + async migrate(toWorkspace: IWorkspaceInitializationPayload): Promise { // not supported } diff --git a/src/vs/platform/storage/electron-sandbox/storageService2.ts b/src/vs/platform/storage/electron-sandbox/storageService2.ts index 5f8efb05026..f025fcb9591 100644 --- a/src/vs/platform/storage/electron-sandbox/storageService2.ts +++ b/src/vs/platform/storage/electron-sandbox/storageService2.ts @@ -3,12 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IDisposable, dispose, MutableDisposable } from 'vs/base/common/lifecycle'; +import { MutableDisposable } from 'vs/base/common/lifecycle'; import { StorageScope, WillSaveStateReason, AbstractStorageService } from 'vs/platform/storage/common/storage'; import { Storage, IStorage } from 'vs/base/parts/storage/common/storage'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IEmptyWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier, IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces'; -import { Promises, RunOnceScheduler, runWhenIdle } from 'vs/base/common/async'; +import { Promises } from 'vs/base/common/async'; import { mark } from 'vs/base/common/performance'; import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services'; import { StorageDatabaseChannelClient } from 'vs/platform/storage/common/storageIpc'; @@ -25,11 +25,6 @@ export class NativeStorageService2 extends AbstractStorageService { private workspaceStorageId: string | undefined = undefined; private workspaceStorageDisposables = this._register(new MutableDisposable()); - private initializePromise: Promise | undefined; - - private readonly periodicFlushScheduler = this._register(new RunOnceScheduler(() => this.doFlushWhenIdle(), 60 * 1000 /* every minute */)); - private runWhenIdleDisposable: IDisposable | undefined = undefined; - constructor( workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined, private readonly mainProcessService: IMainProcessService, @@ -71,15 +66,7 @@ export class NativeStorageService2 extends AbstractStorageService { return undefined; } - initialize(): Promise { - if (!this.initializePromise) { - this.initializePromise = this.doInitialize(); - } - - return this.initializePromise; - } - - private async doInitialize(): Promise { + protected async doInitialize(): Promise { // Init all storage locations mark('code/willInitStorage'); @@ -91,11 +78,6 @@ export class NativeStorageService2 extends AbstractStorageService { } finally { mark('code/didInitStorage'); } - - // On some OS we do not get enough time to persist state on shutdown (e.g. when - // Windows restarts after applying updates). In other cases, VSCode might crash, - // so we periodically save state to reduce the chance of loosing any state. - this.periodicFlushScheduler.schedule(); } protected getStorage(scope: StorageScope): IStorage | undefined { @@ -106,28 +88,10 @@ export class NativeStorageService2 extends AbstractStorageService { return scope === StorageScope.GLOBAL ? this.environmentService.globalStorageHome.fsPath : this.workspaceStorageId ? `${joinPath(this.environmentService.workspaceStorageHome, this.workspaceStorageId, 'state.vscdb').fsPath} [!!! Experimental Main Storage !!!]` : undefined; } - private doFlushWhenIdle(): void { - - // Dispose any previous idle runner - dispose(this.runWhenIdleDisposable); - - // Run when idle - this.runWhenIdleDisposable = runWhenIdle(() => { - - // send event to collect state - this.flush(); - - // repeat - this.periodicFlushScheduler.schedule(); - }); - } - async close(): Promise { // Stop periodic scheduler and idle runner as we now collect state normally - this.periodicFlushScheduler.dispose(); - dispose(this.runWhenIdleDisposable); - this.runWhenIdleDisposable = undefined; + this.stopFlushScheduler(); // Signal as event so that clients can still store data this.emitWillSaveState(WillSaveStateReason.SHUTDOWN); diff --git a/src/vs/platform/storage/node/storageService.ts b/src/vs/platform/storage/node/storageService.ts index 316263b1b52..3d99d334345 100644 --- a/src/vs/platform/storage/node/storageService.ts +++ b/src/vs/platform/storage/node/storageService.ts @@ -15,7 +15,7 @@ import { copy, exists, writeFile } from 'vs/base/node/pfs'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces'; import { assertIsDefined } from 'vs/base/common/types'; -import { Promises, RunOnceScheduler, runWhenIdle } from 'vs/base/common/async'; +import { Promises } from 'vs/base/common/async'; export class NativeStorageService extends AbstractStorageService { @@ -28,13 +28,9 @@ export class NativeStorageService extends AbstractStorageService { private workspaceStorage: IStorage | undefined; private workspaceStorageListener: IDisposable | undefined; - private initializePromise: Promise | undefined; - - private readonly periodicFlushScheduler = this._register(new RunOnceScheduler(() => this.doFlushWhenIdle(), 60000 /* every minute */)); - private runWhenIdleDisposable: IDisposable | undefined = undefined; - constructor( private globalStorageDatabase: IStorageDatabase, + private payload: IWorkspaceInitializationPayload | undefined, @ILogService private readonly logService: ILogService, @IEnvironmentService private readonly environmentService: IEnvironmentService ) { @@ -49,26 +45,13 @@ export class NativeStorageService extends AbstractStorageService { this._register(this.globalStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.GLOBAL, key))); } - initialize(payload?: IWorkspaceInitializationPayload): Promise { - if (!this.initializePromise) { - this.initializePromise = this.doInitialize(payload); - } - - return this.initializePromise; - } - - private async doInitialize(payload?: IWorkspaceInitializationPayload): Promise { + protected async doInitialize(): Promise { // Init all storage locations await Promises.settled([ this.initializeGlobalStorage(), - payload ? this.initializeWorkspaceStorage(payload) : Promise.resolve() + this.payload ? this.initializeWorkspaceStorage(this.payload) : Promise.resolve() ]); - - // On some OS we do not get enough time to persist state on shutdown (e.g. when - // Windows restarts after applying updates). In other cases, VSCode might crash, - // so we periodically save state to reduce the chance of loosing any state. - this.periodicFlushScheduler.schedule(); } private initializeGlobalStorage(): Promise { @@ -178,28 +161,10 @@ export class NativeStorageService extends AbstractStorageService { return scope === StorageScope.GLOBAL ? this.environmentService.globalStorageHome.fsPath : this.workspaceStoragePath; } - private doFlushWhenIdle(): void { - - // Dispose any previous idle runner - dispose(this.runWhenIdleDisposable); - - // Run when idle - this.runWhenIdleDisposable = runWhenIdle(() => { - - // send event to collect state - this.flush(); - - // repeat - this.periodicFlushScheduler.schedule(); - }); - } - async close(): Promise { // Stop periodic scheduler and idle runner as we now collect state normally - this.periodicFlushScheduler.dispose(); - dispose(this.runWhenIdleDisposable); - this.runWhenIdleDisposable = undefined; + this.stopFlushScheduler(); // Signal as event so that clients can still store data this.emitWillSaveState(WillSaveStateReason.SHUTDOWN); diff --git a/src/vs/platform/storage/test/browser/storageService.test.ts b/src/vs/platform/storage/test/browser/storageService.test.ts index fdeb01f61c6..f3e92ff0880 100644 --- a/src/vs/platform/storage/test/browser/storageService.test.ts +++ b/src/vs/platform/storage/test/browser/storageService.test.ts @@ -28,9 +28,9 @@ suite('StorageService (browser)', function () { const userDataProvider = disposables.add(new InMemoryFileSystemProvider()); disposables.add(fileService.registerProvider(Schemas.userData, userDataProvider)); - const storageService = disposables.add(new BrowserStorageService({ userRoamingDataHome: URI.file('/User').with({ scheme: Schemas.userData }) } as unknown as IEnvironmentService, fileService)); + const storageService = disposables.add(new BrowserStorageService({ id: String(Date.now()) }, { userRoamingDataHome: URI.file('/User').with({ scheme: Schemas.userData }) } as unknown as IEnvironmentService, fileService)); - await storageService.initialize({ id: String(Date.now()) }); + await storageService.initialize(); return storageService; }, diff --git a/src/vs/platform/storage/test/node/storageService.test.ts b/src/vs/platform/storage/test/node/storageService.test.ts index ce8eb321aac..68ba513e051 100644 --- a/src/vs/platform/storage/test/node/storageService.test.ts +++ b/src/vs/platform/storage/test/node/storageService.test.ts @@ -42,8 +42,8 @@ flakySuite('StorageService (native)', function () { await promises.mkdir(testDir, { recursive: true }); - const storageService = new NativeStorageService(new InMemoryStorageDatabase(), new NullLogService(), new StorageTestEnvironmentService(URI.file(testDir), testDir)); - await storageService.initialize({ id: String(Date.now()) }); + const storageService = new NativeStorageService(new InMemoryStorageDatabase(), { id: String(Date.now()) }, new NullLogService(), new StorageTestEnvironmentService(URI.file(testDir), testDir)); + await storageService.initialize(); return storageService; }, @@ -55,8 +55,8 @@ flakySuite('StorageService (native)', function () { }); test('Migrate Data', async function () { - const storage = new NativeStorageService(new InMemoryStorageDatabase(), new NullLogService(), new StorageTestEnvironmentService(URI.file(testDir), testDir)); - await storage.initialize({ id: String(Date.now()) }); + const storage = new NativeStorageService(new InMemoryStorageDatabase(), { id: String(Date.now()) }, new NullLogService(), new StorageTestEnvironmentService(URI.file(testDir), testDir)); + await storage.initialize(); storage.store('bar', 'foo', StorageScope.WORKSPACE, StorageTarget.MACHINE); storage.store('barNumber', 55, StorageScope.WORKSPACE, StorageTarget.MACHINE); diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index bdecdbc0c90..9aea863b585 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -302,10 +302,10 @@ class BrowserMain extends Disposable { } private async createStorageService(payload: IWorkspaceInitializationPayload, environmentService: IWorkbenchEnvironmentService, fileService: IFileService, logService: ILogService): Promise { - const storageService = new BrowserStorageService(environmentService, fileService); + const storageService = new BrowserStorageService(payload, environmentService, fileService); try { - await storageService.initialize(payload); + await storageService.initialize(); return storageService; } catch (error) { diff --git a/src/vs/workbench/electron-browser/desktop.main.ts b/src/vs/workbench/electron-browser/desktop.main.ts index 103816e95c0..bcd53444318 100644 --- a/src/vs/workbench/electron-browser/desktop.main.ts +++ b/src/vs/workbench/electron-browser/desktop.main.ts @@ -329,11 +329,11 @@ class DesktopMain extends Disposable { storageService = new NativeStorageService2(payload, mainProcessService, this.environmentService); } else { const storageDataBaseClient = new StorageDatabaseChannelClient(mainProcessService.getChannel('storage'), payload); - storageService = new NativeStorageService(storageDataBaseClient.globalStorage, logService, this.environmentService); + storageService = new NativeStorageService(storageDataBaseClient.globalStorage, payload, logService, this.environmentService); } try { - await storageService.initialize(payload); + await storageService.initialize(); return storageService; } catch (error) { From 3f0d8a14759cddea93f0dbddc12a4ef1e5586e86 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 17 Feb 2021 08:21:44 +0100 Subject: [PATCH 242/325] storage - some :lipstick: --- .../storage/browser/storageService.ts | 2 +- src/vs/platform/storage/common/storage.ts | 14 ++++++------- src/vs/platform/storage/common/storageIpc.ts | 19 ++++++++++++++++-- .../electron-sandbox/storageService2.ts | 20 +++++++++---------- .../platform/storage/node/storageService.ts | 2 +- 5 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/vs/platform/storage/browser/storageService.ts b/src/vs/platform/storage/browser/storageService.ts index 8c60c691d1f..5cfb899602e 100644 --- a/src/vs/platform/storage/browser/storageService.ts +++ b/src/vs/platform/storage/browser/storageService.ts @@ -94,7 +94,7 @@ export class BrowserStorageService extends AbstractStorageService { throw new Error('Migrating storage is currently unsupported in Web'); } - protected shouldScheduleFlush(): boolean { + protected shouldFlushWhenIdle(): boolean { // this flush() will potentially cause new state to be stored // since new state will only be created while the document // has focus, one optimization is to not run this when the diff --git a/src/vs/platform/storage/common/storage.ts b/src/vs/platform/storage/common/storage.ts index ce08361d389..faecb2618ea 100644 --- a/src/vs/platform/storage/common/storage.ts +++ b/src/vs/platform/storage/common/storage.ts @@ -241,7 +241,7 @@ export abstract class AbstractStorageService extends Disposable implements IStor private initializationPromise: Promise | undefined; - private readonly flushScheduler = this._register(new RunOnceScheduler(() => this.doFlushWhenIdle(), this.options.flushInterval)); + private readonly flushWhenIdleScheduler = this._register(new RunOnceScheduler(() => this.doFlushWhenIdle(), this.options.flushInterval)); private readonly runFlushWhenIdle = this._register(new MutableDisposable()); constructor(private options: IStorageServiceOptions = { flushInterval: AbstractStorageService.DEFAULT_FLUSH_INTERVAL }) { @@ -250,21 +250,21 @@ export abstract class AbstractStorageService extends Disposable implements IStor private doFlushWhenIdle(): void { this.runFlushWhenIdle.value = runWhenIdle(() => { - if (this.shouldScheduleFlush()) { + if (this.shouldFlushWhenIdle()) { this.flush(); } // repeat - this.flushScheduler.schedule(); + this.flushWhenIdleScheduler.schedule(); }); } - protected shouldScheduleFlush(): boolean { + protected shouldFlushWhenIdle(): boolean { return true; } - protected stopFlushScheduler(): void { - dispose([this.runFlushWhenIdle, this.flushScheduler]); + protected stopFlushWhenIdle(): void { + dispose([this.runFlushWhenIdle, this.flushWhenIdleScheduler]); } initialize(): Promise { @@ -282,7 +282,7 @@ export abstract class AbstractStorageService extends Disposable implements IStor // long running operation. // Instead, periodically ask customers to save save. The library will be clever enough // to only save state that has actually changed. - this.flushScheduler.schedule(); + this.flushWhenIdleScheduler.schedule(); })(); } diff --git a/src/vs/platform/storage/common/storageIpc.ts b/src/vs/platform/storage/common/storageIpc.ts index 8ff562fc44f..a95938a3ae5 100644 --- a/src/vs/platform/storage/common/storageIpc.ts +++ b/src/vs/platform/storage/common/storageIpc.ts @@ -109,8 +109,23 @@ class WorkspaceStorageDatabaseClient extends BaseStorageDatabaseClient implement export class StorageDatabaseChannelClient extends Disposable { - readonly globalStorage = new GlobalStorageDatabaseClient(this.channel); - readonly workspaceStorage = this.workspace ? new WorkspaceStorageDatabaseClient(this.channel, this.workspace) : undefined; + private _globalStorage: GlobalStorageDatabaseClient | undefined = undefined; + get globalStorage() { + if (!this._globalStorage) { + this._globalStorage = new GlobalStorageDatabaseClient(this.channel); + } + + return this._globalStorage; + } + + private _workspaceStorage: WorkspaceStorageDatabaseClient | undefined = undefined; + get workspaceStorage() { + if (!this._workspaceStorage && this.workspace) { + this._workspaceStorage = new WorkspaceStorageDatabaseClient(this.channel, this.workspace); + } + + return this._workspaceStorage; + } constructor( private channel: IChannel, diff --git a/src/vs/platform/storage/electron-sandbox/storageService2.ts b/src/vs/platform/storage/electron-sandbox/storageService2.ts index f025fcb9591..f8d6e9ae7c3 100644 --- a/src/vs/platform/storage/electron-sandbox/storageService2.ts +++ b/src/vs/platform/storage/electron-sandbox/storageService2.ts @@ -23,7 +23,7 @@ export class NativeStorageService2 extends AbstractStorageService { // in the current window, when entering a workspace! private workspaceStorage: IStorage | undefined = undefined; private workspaceStorageId: string | undefined = undefined; - private workspaceStorageDisposables = this._register(new MutableDisposable()); + private workspaceStorageDisposable = this._register(new MutableDisposable()); constructor( workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined, @@ -49,21 +49,21 @@ export class NativeStorageService2 extends AbstractStorageService { private createWorkspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier): IStorage; private createWorkspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined): IStorage | undefined; private createWorkspaceStorage(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined): IStorage | undefined { - - // Keep id around for logging - this.workspaceStorageId = workspace?.id; - - // Create new const storageDataBaseClient = new StorageDatabaseChannelClient(this.mainProcessService.getChannel('storage'), workspace); + if (storageDataBaseClient.workspaceStorage) { const workspaceStorage = new Storage(storageDataBaseClient.workspaceStorage); - this.workspaceStorageDisposables.value = workspaceStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.WORKSPACE, key)); + this.workspaceStorageDisposable.value = workspaceStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.WORKSPACE, key)); + this.workspaceStorageId = workspace?.id; return workspaceStorage; - } + } else { + this.workspaceStorageDisposable.clear(); + this.workspaceStorageId = undefined; - return undefined; + return undefined; + } } protected async doInitialize(): Promise { @@ -91,7 +91,7 @@ export class NativeStorageService2 extends AbstractStorageService { async close(): Promise { // Stop periodic scheduler and idle runner as we now collect state normally - this.stopFlushScheduler(); + this.stopFlushWhenIdle(); // Signal as event so that clients can still store data this.emitWillSaveState(WillSaveStateReason.SHUTDOWN); diff --git a/src/vs/platform/storage/node/storageService.ts b/src/vs/platform/storage/node/storageService.ts index 3d99d334345..3b33b0ba27b 100644 --- a/src/vs/platform/storage/node/storageService.ts +++ b/src/vs/platform/storage/node/storageService.ts @@ -164,7 +164,7 @@ export class NativeStorageService extends AbstractStorageService { async close(): Promise { // Stop periodic scheduler and idle runner as we now collect state normally - this.stopFlushScheduler(); + this.stopFlushWhenIdle(); // Signal as event so that clients can still store data this.emitWillSaveState(WillSaveStateReason.SHUTDOWN); From 89b85a05d4320f297600a36c3b3010a6f8c9978d Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 17 Feb 2021 10:23:52 +0100 Subject: [PATCH 243/325] storage - more consolidation --- .../storage/electron-main/storageIpc.ts | 7 +- .../storage/electron-main/storageMain.ts | 124 +++++++----------- .../electron-main/storageMainService.ts | 4 +- .../electron-main/storageMainService.test.ts | 54 ++++++-- .../platform/windows/electron-main/window.ts | 2 +- 5 files changed, 97 insertions(+), 94 deletions(-) diff --git a/src/vs/platform/storage/electron-main/storageIpc.ts b/src/vs/platform/storage/electron-main/storageIpc.ts index 551953afbd0..f8a6224c5c7 100644 --- a/src/vs/platform/storage/electron-main/storageIpc.ts +++ b/src/vs/platform/storage/electron-main/storageIpc.ts @@ -91,14 +91,15 @@ export class StorageDatabaseChannel extends Disposable implements IServerChannel case 'updateItems': { const items: ISerializableUpdateRequest = arg; + if (items.insert) { for (const [key, value] of items.insert) { - storage.store(key, value); + storage.set(key, value); } } if (items.delete) { - items.delete.forEach(key => storage.remove(key)); + items.delete.forEach(key => storage.delete(key)); } break; @@ -125,7 +126,7 @@ export class StorageDatabaseChannel extends Disposable implements IServerChannel const storage = workspace ? this.storageMainService.workspaceStorage(workspace) : this.storageMainService.globalStorage; try { - await storage.initialize(); + await storage.init(); } catch (error) { this.logService.error(`StorageIPC#init: Unable to init ${workspace ? 'workspace' : 'global'} storage due to ${error}`); } diff --git a/src/vs/platform/storage/electron-main/storageMain.ts b/src/vs/platform/storage/electron-main/storageMain.ts index 9d1f5c1b6ce..c9a430dccef 100644 --- a/src/vs/platform/storage/electron-main/storageMain.ts +++ b/src/vs/platform/storage/electron-main/storageMain.ts @@ -50,7 +50,7 @@ export interface IStorageMain extends IDisposable { /** * Required call to ensure the service can be used. */ - initialize(): Promise; + init(): Promise; /** * Retrieve an element stored with the given key from storage. Use @@ -59,32 +59,16 @@ export interface IStorageMain extends IDisposable { get(key: string, fallbackValue: string): string; get(key: string, fallbackValue?: string): string | undefined; - /** - * Retrieve an element stored with the given key from storage. Use - * the provided defaultValue if the element is null or undefined. The element - * will be converted to a boolean. - */ - getBoolean(key: string, fallbackValue: boolean): boolean; - getBoolean(key: string, fallbackValue?: boolean): boolean | undefined; - - /** - * Retrieve an element stored with the given key from storage. Use - * the provided defaultValue if the element is null or undefined. The element - * will be converted to a number using parseInt with a base of 10. - */ - getNumber(key: string, fallbackValue: number): number; - getNumber(key: string, fallbackValue?: number): number | undefined; - /** * Store a string value under the given key to storage. The value will * be converted to a string. */ - store(key: string, value: string | boolean | number | undefined | null): void; + set(key: string, value: string | boolean | number | undefined | null): void; /** * Delete an element stored under the provided key from storage. */ - remove(key: string): void; + delete(key: string): void; /** * Close the storage connection. @@ -114,17 +98,26 @@ abstract class BaseStorageMain extends Disposable implements IStorageMain { super(); } - initialize(): Promise { + init(): Promise { if (!this.initializePromise) { this.initializePromise = (async () => { try { - const storage = await this.doInitialize(); - // Replace our in-memory storage with the initialized - // one once that is finished and use it from then on + // Create storage via subclasses + const storage = await this.doCreate(); + + // Replace our in-memory storage with the real + // once as soon as possible without awaiting + // the init call. this.storage.dispose(); this.storage = storage; + // Re-emit storage changes via event + this._register(storage.onDidChangeStorage(key => this._onDidChangeStorage.fire({ key }))); + + // Await storage init + await this.doInit(storage); + // Ensure we track wether storage is new or not const isNewStorage = storage.getBoolean(IS_NEW_KEY); if (isNewStorage === undefined) { @@ -148,7 +141,11 @@ abstract class BaseStorageMain extends Disposable implements IStorageMain { }; } - protected abstract doInitialize(): Promise; + protected doInit(storage: IStorage): Promise { + return storage.init(); + } + + protected abstract doCreate(): Promise; get items(): Map { return this.storage.items; } @@ -158,28 +155,24 @@ abstract class BaseStorageMain extends Disposable implements IStorageMain { return this.storage.get(key, fallbackValue); } - getBoolean(key: string, fallbackValue: boolean): boolean; - getBoolean(key: string, fallbackValue?: boolean): boolean | undefined; - getBoolean(key: string, fallbackValue?: boolean): boolean | undefined { - return this.storage.getBoolean(key, fallbackValue); - } - - getNumber(key: string, fallbackValue: number): number; - getNumber(key: string, fallbackValue?: number): number | undefined; - getNumber(key: string, fallbackValue?: number): number | undefined { - return this.storage.getNumber(key, fallbackValue); - } - - store(key: string, value: string | boolean | number | undefined | null): Promise { + set(key: string, value: string | boolean | number | undefined | null): Promise { return this.storage.set(key, value); } - remove(key: string): Promise { + delete(key: string): Promise { return this.storage.delete(key); } async close(): Promise { + // Ensure we are not accidentally leaving + // a pending initialized storage behind in + // case close() was called before init() + // finishes + if (this.initializePromise) { + await this.initializePromise; + } + // Propagate to storage lib await this.storage.close(); @@ -200,7 +193,7 @@ export class GlobalStorageMain extends BaseStorageMain implements IStorageMain { super(logService); } - protected async doInitialize(): Promise { + protected async doCreate(): Promise { let storagePath: string; if (this.options.useInMemoryStorage) { storagePath = SQLiteStorageDatabase.IN_MEMORY_PATH; @@ -208,24 +201,19 @@ export class GlobalStorageMain extends BaseStorageMain implements IStorageMain { storagePath = join(this.environmentService.globalStorageHome.fsPath, GlobalStorageMain.STORAGE_NAME); } - // Create Storage - const storage = new Storage(new SQLiteStorageDatabase(storagePath, { + return new Storage(new SQLiteStorageDatabase(storagePath, { logging: this.createLogginOptions() })); + } - // Re-emit storage changes via event - this._register(storage.onDidChangeStorage(key => this._onDidChangeStorage.fire({ key }))); - - // Forward init to SQLite DB - await storage.init(); + protected async doInit(storage: IStorage): Promise { + await super.doInit(storage); // Apply global telemetry values as part of the initialization this.updateTelemetryState(storage); - - return storage; } - private updateTelemetryState(storage: Storage): void { + private updateTelemetryState(storage: IStorage): void { // Instance UUID (once) const instanceId = storage.get(instanceStorageKey, undefined); @@ -263,23 +251,12 @@ export class WorkspaceStorageMain extends BaseStorageMain implements IStorageMai super(logService); } - protected async doInitialize(): Promise { - - // Prepare workspace storage folder for DB + protected async doCreate(): Promise { const { storageFilePath, wasCreated } = await this.prepareWorkspaceStorageFolder(); - // Create Storage - const storage = new Storage(new SQLiteStorageDatabase(storageFilePath, { + return new Storage(new SQLiteStorageDatabase(storageFilePath, { logging: this.createLogginOptions() }), { hint: wasCreated ? StorageHint.STORAGE_DOES_NOT_EXIST : undefined }); - - // Re-emit storage changes via event - this._register(storage.onDidChangeStorage(key => this._onDidChangeStorage.fire({ key }))); - - // Forward init to SQLite DB - await storage.init(); - - return storage; } private async prepareWorkspaceStorageFolder(): Promise<{ storageFilePath: string, wasCreated: boolean }> { @@ -298,15 +275,16 @@ export class WorkspaceStorageMain extends BaseStorageMain implements IStorageMai return { storageFilePath: workspaceStorageDatabasePath, wasCreated: false }; } + // Ensure storage folder exists await promises.mkdir(workspaceStorageFolderPath, { recursive: true }); - // Write metadata into folder + // Write metadata into folder (but do not await) this.ensureWorkspaceStorageFolderMeta(workspaceStorageFolderPath); return { storageFilePath: workspaceStorageDatabasePath, wasCreated: true }; } - private ensureWorkspaceStorageFolderMeta(workspaceStorageFolderPath: string): void { + private async ensureWorkspaceStorageFolderMeta(workspaceStorageFolderPath: string): Promise { let meta: object | undefined = undefined; if (isSingleFolderWorkspaceIdentifier(this.workspace)) { meta = { folder: this.workspace.uri.toString() }; @@ -315,17 +293,15 @@ export class WorkspaceStorageMain extends BaseStorageMain implements IStorageMai } if (meta) { - (async () => { - try { - const workspaceStorageMetaPath = join(workspaceStorageFolderPath, WorkspaceStorageMain.WORKSPACE_META_NAME); - const storageExists = await exists(workspaceStorageMetaPath); - if (!storageExists) { - await writeFile(workspaceStorageMetaPath, JSON.stringify(meta, undefined, 2)); - } - } catch (error) { - this.logService.error(`StorageMain#ensureWorkspaceStorageFolderMeta(): Unable to create workspace storage metadata due to ${error}`); + try { + const workspaceStorageMetaPath = join(workspaceStorageFolderPath, WorkspaceStorageMain.WORKSPACE_META_NAME); + const storageExists = await exists(workspaceStorageMetaPath); + if (!storageExists) { + await writeFile(workspaceStorageMetaPath, JSON.stringify(meta, undefined, 2)); } - })(); + } catch (error) { + this.logService.error(`StorageMain#ensureWorkspaceStorageFolderMeta(): Unable to create workspace storage metadata due to ${error}`); + } } } } diff --git a/src/vs/platform/storage/electron-main/storageMainService.ts b/src/vs/platform/storage/electron-main/storageMainService.ts index a82e8efd0a8..842bee97c24 100644 --- a/src/vs/platform/storage/electron-main/storageMainService.ts +++ b/src/vs/platform/storage/electron-main/storageMainService.ts @@ -62,14 +62,14 @@ export class StorageMainService extends Disposable implements IStorageMainServic (async () => { await this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen); - this.globalStorage.initialize(); + this.globalStorage.init(); })(); // Workspace Storage: Warmup when related window with workspace loads if (this.enableMainWorkspaceStorage()) { this._register(this.lifecycleMainService.onWillLoadWindow(async e => { if (e.workspace) { - this.workspaceStorage(e.workspace).initialize(); + this.workspaceStorage(e.workspace).init(); } })); } diff --git a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts index a0aa7f151d3..2a91d25b5d9 100644 --- a/src/vs/platform/storage/test/electron-main/storageMainService.test.ts +++ b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts @@ -81,12 +81,12 @@ suite('StorageMainService', function () { if (isGlobal) { strictEqual(storage.items.size, 0); strictEqual(storage.get(instanceStorageKey), undefined); - await storage.initialize(); + await storage.init(); strictEqual(typeof storage.get(instanceStorageKey), 'string'); strictEqual(typeof storage.get(firstSessionDateStorageKey), 'string'); strictEqual(typeof storage.get(currentSessionDateStorageKey), 'string'); } else { - await storage.initialize(); + await storage.init(); } let storageChangeEvent: IStorageChangeEvent | undefined = undefined; @@ -100,24 +100,24 @@ suite('StorageMainService', function () { // Basic store/get/remove const size = storage.items.size; - storage.store('bar', 'foo'); + storage.set('bar', 'foo'); strictEqual(storageChangeEvent!.key, 'bar'); - storage.store('barNumber', 55); - storage.store('barBoolean', true); + storage.set('barNumber', 55); + storage.set('barBoolean', true); strictEqual(storage.get('bar'), 'foo'); - strictEqual(storage.getNumber('barNumber'), 55); - strictEqual(storage.getBoolean('barBoolean'), true); + strictEqual(storage.get('barNumber'), '55'); + strictEqual(storage.get('barBoolean'), 'true'); strictEqual(storage.items.size, size + 3); - storage.remove('bar'); + storage.delete('bar'); strictEqual(storage.get('bar'), undefined); strictEqual(storage.items.size, size + 2); // IS_NEW - strictEqual(storage.getBoolean(IS_NEW_KEY), true); + strictEqual(storage.get(IS_NEW_KEY), 'true'); // Close await storage.close(); @@ -160,8 +160,8 @@ suite('StorageMainService', function () { strictEqual(workspaceStorage, storageMainService.workspaceStorage(workspace)); // same instance as long as not closed - await globalStorage.initialize(); - await workspaceStorage.initialize(); + await globalStorage.init(); + await workspaceStorage.init(); await lifecycleMainService.fireOnWillShutdown(); @@ -184,13 +184,39 @@ suite('StorageMainService', function () { didCloseWorkspaceStorage = true; }); - let globalStorage1 = storageMainService.globalStorage; + let globalStorage = storageMainService.globalStorage; let didCloseGlobalStorage = false; - globalStorage1.onDidCloseStorage(() => { + globalStorage.onDidCloseStorage(() => { didCloseGlobalStorage = true; }); - await globalStorage1.close(); + await globalStorage.close(); + await workspaceStorage.close(); + + strictEqual(didCloseGlobalStorage, true); + strictEqual(didCloseWorkspaceStorage, true); + }); + + test('storage closed before init awaits works', async function () { + const storageMainService = new TestStorageMainService(new NullLogService(), new NativeEnvironmentService(parseArgs(process.argv, OPTIONS)), new StorageTestLifecycleMainService(), new TestConfigurationService()); + const workspace = { id: generateUuid() }; + + let workspaceStorage = storageMainService.workspaceStorage(workspace); + let didCloseWorkspaceStorage = false; + workspaceStorage.onDidCloseStorage(() => { + didCloseWorkspaceStorage = true; + }); + + let globalStorage = storageMainService.globalStorage; + let didCloseGlobalStorage = false; + globalStorage.onDidCloseStorage(() => { + didCloseGlobalStorage = true; + }); + + globalStorage.init(); + workspaceStorage.init(); + + await globalStorage.close(); await workspaceStorage.close(); strictEqual(didCloseGlobalStorage, true); diff --git a/src/vs/platform/windows/electron-main/window.ts b/src/vs/platform/windows/electron-main/window.ts index a78accbef8e..c386a584857 100644 --- a/src/vs/platform/windows/electron-main/window.ts +++ b/src/vs/platform/windows/electron-main/window.ts @@ -269,7 +269,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { // Request handling this.marketplaceHeadersPromise = resolveMarketplaceHeaders(product.version, this.environmentMainService, this.fileService, { get: key => storageMainService.globalStorage.get(key), - store: (key, value) => storageMainService.globalStorage.store(key, value) + store: (key, value) => storageMainService.globalStorage.set(key, value) }); // Eventing From 7a0caf4d86e400d82e401c8c37f36ae510145134 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Wed, 17 Feb 2021 10:33:46 +0100 Subject: [PATCH 244/325] Let Remote extensions set port source (#116838) --- src/vs/vscode.proposed.d.ts | 8 ++++ .../api/browser/mainThreadTunnelService.ts | 37 ++++++++++++++++--- .../workbench/api/common/extHost.api.impl.ts | 3 +- .../workbench/api/common/extHost.protocol.ts | 7 ++++ .../api/node/extHostTunnelService.ts | 3 ++ .../contrib/remote/browser/remoteExplorer.ts | 6 +-- .../contrib/remote/browser/tunnelView.ts | 3 +- .../remote/common/remoteExplorerService.ts | 4 ++ 8 files changed, 60 insertions(+), 11 deletions(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 341b5b78df6..bf24ab9b655 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -204,6 +204,12 @@ declare module 'vscode' { elevationRequired?: boolean; } + export enum CandidatePortSource { + None = 0, + Process = 1, + Output = 2 + } + export type ResolverResult = ResolvedAuthority & ResolvedOptions & TunnelInformation; export class RemoteAuthorityResolverError extends Error { @@ -238,6 +244,8 @@ declare module 'vscode' { elevation: boolean; public: boolean; }; + + candidatePortSource?: CandidatePortSource; } export namespace workspace { diff --git a/src/vs/workbench/api/browser/mainThreadTunnelService.ts b/src/vs/workbench/api/browser/mainThreadTunnelService.ts index bc7c653b981..052f5a24516 100644 --- a/src/vs/workbench/api/browser/mainThreadTunnelService.ts +++ b/src/vs/workbench/api/browser/mainThreadTunnelService.ts @@ -4,17 +4,17 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import { MainThreadTunnelServiceShape, IExtHostContext, MainContext, ExtHostContext, ExtHostTunnelServiceShape } from 'vs/workbench/api/common/extHost.protocol'; +import { MainThreadTunnelServiceShape, IExtHostContext, MainContext, ExtHostContext, ExtHostTunnelServiceShape, CandidatePortSource } from 'vs/workbench/api/common/extHost.protocol'; import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; -import { CandidatePort, IRemoteExplorerService, makeAddress } from 'vs/workbench/services/remote/common/remoteExplorerService'; +import { CandidatePort, IRemoteExplorerService, makeAddress, PORT_AUTO_FORWARD_SETTING, PORT_AUTO_SOURCE_SETTING, PORT_AUTO_SOURCE_SETTING_OUTPUT } from 'vs/workbench/services/remote/common/remoteExplorerService'; import { ITunnelProvider, ITunnelService, TunnelCreationOptions, TunnelProviderFeatures, TunnelOptions, RemoteTunnel, isPortPrivileged } from 'vs/platform/remote/common/tunnel'; import { Disposable } from 'vs/base/common/lifecycle'; import type { TunnelDescription } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { PORT_AUTO_FORWARD_SETTING } from 'vs/workbench/contrib/remote/browser/tunnelView'; +import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILogService } from 'vs/platform/log/common/log'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; @extHostNamedCustomer(MainContext.MainThreadTunnelService) export class MainThreadTunnelService extends Disposable implements MainThreadTunnelServiceShape { @@ -27,7 +27,8 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun @ITunnelService private readonly tunnelService: ITunnelService, @INotificationService private readonly notificationService: INotificationService, @IConfigurationService private readonly configurationService: IConfigurationService, - @ILogService private readonly logService: ILogService + @ILogService private readonly logService: ILogService, + @IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService ) { super(); this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTunnelService); @@ -132,6 +133,32 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun }); } + async $setCandidatePortSource(source: CandidatePortSource): Promise { + // Must wait for the remote environment before trying to set settings there. + this.remoteAgentService.getEnvironment().then(() => { + switch (source) { + case CandidatePortSource.None: { + const autoDetectionEnablement = this.configurationService.inspect(PORT_AUTO_FORWARD_SETTING); + if (autoDetectionEnablement.userRemote === undefined) { + // Only update the remote setting if the user hasn't already set it. + this.configurationService.updateValue(PORT_AUTO_FORWARD_SETTING, false, ConfigurationTarget.USER_REMOTE); + } + break; + } + case CandidatePortSource.Output: { + const candidatePortSourceSetting = this.configurationService.inspect(PORT_AUTO_SOURCE_SETTING); + if (candidatePortSourceSetting.userRemote === undefined) { + // Only update the remote setting if the user hasn't already set it. + this.configurationService.updateValue(PORT_AUTO_SOURCE_SETTING, PORT_AUTO_SOURCE_SETTING_OUTPUT, ConfigurationTarget.USER_REMOTE); + } + break; + } + default: // Do nothing, the defaults for these settings should be used. + } + }).catch(() => { + // The remote failed to get setup. Errors from that area will already be surfaced to the user. + }); + } dispose(): void { diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 9b95c71438e..32d13f792e0 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -15,7 +15,7 @@ import { OverviewRulerLane } from 'vs/editor/common/model'; import * as languageConfiguration from 'vs/editor/common/modes/languageConfiguration'; import { score } from 'vs/editor/common/modes/languageSelector'; import * as files from 'vs/platform/files/common/files'; -import { ExtHostContext, MainContext, ExtHostLogServiceShape, UIKind } from 'vs/workbench/api/common/extHost.protocol'; +import { ExtHostContext, MainContext, ExtHostLogServiceShape, UIKind, CandidatePortSource } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostApiCommands } from 'vs/workbench/api/common/extHostApiCommands'; import { ExtHostClipboard } from 'vs/workbench/api/common/extHostClipboard'; import { IExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; @@ -1134,6 +1134,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I CallHierarchyOutgoingCall: extHostTypes.CallHierarchyOutgoingCall, CancellationError: errors.CancellationError, CancellationTokenSource: CancellationTokenSource, + CandidatePortSource: CandidatePortSource, CodeAction: extHostTypes.CodeAction, CodeActionKind: extHostTypes.CodeActionKind, CodeActionTrigger: extHostTypes.CodeActionTrigger, diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index ceef2474341..fdb63d9c2d2 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -992,6 +992,12 @@ export interface MainThreadWindowShape extends IDisposable { $asExternalUri(uri: UriComponents, options: IOpenUriOptions): Promise; } +export enum CandidatePortSource { + None = 0, + Process = 1, + Output = 2 +} + export interface MainThreadTunnelServiceShape extends IDisposable { $openTunnel(tunnelOptions: TunnelOptions, source: string | undefined): Promise; $closeTunnel(remote: { host: string, port: number }): Promise; @@ -1000,6 +1006,7 @@ export interface MainThreadTunnelServiceShape extends IDisposable { $setRemoteTunnelService(processId: number): Promise; $setCandidateFilter(): Promise; $onFoundNewCandidates(candidates: { host: string, port: number, detail: string }[]): Promise; + $setCandidatePortSource(source: CandidatePortSource): Promise; } export interface MainThreadTimelineShape extends IDisposable { diff --git a/src/vs/workbench/api/node/extHostTunnelService.ts b/src/vs/workbench/api/node/extHostTunnelService.ts index c0cc5d43940..9b9dd79dc9c 100644 --- a/src/vs/workbench/api/node/extHostTunnelService.ts +++ b/src/vs/workbench/api/node/extHostTunnelService.ts @@ -196,6 +196,9 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe async setTunnelExtensionFunctions(provider: vscode.RemoteAuthorityResolver | undefined): Promise { if (provider) { + if (provider.candidatePortSource !== undefined) { + await this._proxy.$setCandidatePortSource(provider.candidatePortSource); + } if (provider.showCandidatePort) { this._showCandidatePort = provider.showCandidatePort; await this._proxy.$setCandidateFilter(); diff --git a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts index 89a5e8545f4..e0c1a0c44cb 100644 --- a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts +++ b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts @@ -6,8 +6,8 @@ import * as nls from 'vs/nls'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { Extensions, IViewContainersRegistry, IViewDescriptorService, IViewsRegistry, IViewsService, ViewContainer, ViewContainerLocation } from 'vs/workbench/common/views'; -import { IRemoteExplorerService, makeAddress, mapHasAddressLocalhostOrAllInterfaces, OnPortForward, PortsAttributes, TUNNEL_VIEW_ID } from 'vs/workbench/services/remote/common/remoteExplorerService'; -import { PORT_AUTO_FORWARD_SETTING, forwardedPortsViewEnabled, ForwardPortAction, OpenPortInBrowserAction, TunnelPanel, TunnelPanelDescriptor, TunnelViewModel, OpenPortInPreviewAction } from 'vs/workbench/contrib/remote/browser/tunnelView'; +import { IRemoteExplorerService, makeAddress, mapHasAddressLocalhostOrAllInterfaces, OnPortForward, PortsAttributes, PORT_AUTO_FORWARD_SETTING, PORT_AUTO_SOURCE_SETTING, PORT_AUTO_SOURCE_SETTING_PROCESS, TUNNEL_VIEW_ID } from 'vs/workbench/services/remote/common/remoteExplorerService'; +import { forwardedPortsViewEnabled, ForwardPortAction, OpenPortInBrowserAction, TunnelPanel, TunnelPanelDescriptor, TunnelViewModel, OpenPortInPreviewAction } from 'vs/workbench/contrib/remote/browser/tunnelView'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -219,7 +219,7 @@ export class AutomaticPortForwarding extends Disposable implements IWorkbenchCon this._register(new OutputAutomaticPortForwarding(terminalService, notificationService, openerService, externalOpenerService, remoteExplorerService, configurationService, debugService, tunnelService, remoteAgentService, hostService, false)); } else if (environment?.os === OperatingSystem.Linux) { - const useProc = (this.configurationService.getValue('remote.autoForwardPortsSource') === 'process'); + const useProc = (this.configurationService.getValue(PORT_AUTO_SOURCE_SETTING) === PORT_AUTO_SOURCE_SETTING_PROCESS); if (useProc) { this._register(new ProcAutomaticPortForwarding(configurationService, remoteExplorerService, notificationService, openerService, externalOpenerService, tunnelService, hostService)); diff --git a/src/vs/workbench/contrib/remote/browser/tunnelView.ts b/src/vs/workbench/contrib/remote/browser/tunnelView.ts index daa3fba23f9..d0fb151868d 100644 --- a/src/vs/workbench/contrib/remote/browser/tunnelView.ts +++ b/src/vs/workbench/contrib/remote/browser/tunnelView.ts @@ -26,7 +26,7 @@ import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { ActionRunner, IAction } from 'vs/base/common/actions'; import { IMenuService, MenuId, IMenu, MenuRegistry, ILocalizedString, Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { createAndFillInContextMenuActions, createAndFillInActionBarActions, createActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; -import { IRemoteExplorerService, TunnelModel, makeAddress, TunnelType, ITunnelItem, Tunnel, mapHasAddressLocalhostOrAllInterfaces, TUNNEL_VIEW_ID, parseAddress, CandidatePort, TunnelPrivacy } from 'vs/workbench/services/remote/common/remoteExplorerService'; +import { IRemoteExplorerService, TunnelModel, makeAddress, TunnelType, ITunnelItem, Tunnel, mapHasAddressLocalhostOrAllInterfaces, TUNNEL_VIEW_ID, parseAddress, CandidatePort, TunnelPrivacy, PORT_AUTO_FORWARD_SETTING } from 'vs/workbench/services/remote/common/remoteExplorerService'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { InputBox, MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; @@ -48,7 +48,6 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { isWeb } from 'vs/base/common/platform'; export const forwardedPortsViewEnabled = new RawContextKey('forwardedPortsViewEnabled', false); -export const PORT_AUTO_FORWARD_SETTING = 'remote.autoForwardPorts'; class TunnelTreeVirtualDelegate implements IListVirtualDelegate { getHeight(element: ITunnelItem): number { diff --git a/src/vs/workbench/services/remote/common/remoteExplorerService.ts b/src/vs/workbench/services/remote/common/remoteExplorerService.ts index 1ced7e337bf..f3420ff3d97 100644 --- a/src/vs/workbench/services/remote/common/remoteExplorerService.ts +++ b/src/vs/workbench/services/remote/common/remoteExplorerService.ts @@ -23,6 +23,10 @@ export const IRemoteExplorerService = createDecorator('r export const REMOTE_EXPLORER_TYPE_KEY: string = 'remote.explorerType'; const TUNNELS_TO_RESTORE = 'remote.tunnels.toRestore'; export const TUNNEL_VIEW_ID = '~remote.forwardedPorts'; +export const PORT_AUTO_FORWARD_SETTING = 'remote.autoForwardPorts'; +export const PORT_AUTO_SOURCE_SETTING = 'remote.autoForwardPortsSource'; +export const PORT_AUTO_SOURCE_SETTING_PROCESS = 'process'; +export const PORT_AUTO_SOURCE_SETTING_OUTPUT = 'output'; export enum TunnelType { Candidate = 'Candidate', From 1bf78c50fe9ec9cd526ed97f723cf4e0bbc2ae7b Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 17 Feb 2021 10:35:50 +0100 Subject: [PATCH 245/325] add NotebookCellOutput#metadata, also use API type internally and translate dto sooner, fixes https://github.com/microsoft/vscode/issues/116792 --- src/vs/vscode.proposed.d.ts | 10 +++-- .../api/common/extHostNotebookDocument.ts | 18 ++++----- .../api/common/extHostTypeConverters.ts | 37 ++++++++++--------- src/vs/workbench/api/common/extHostTypes.ts | 26 ++++++++++--- .../model/notebookCellOutputTextModel.ts | 12 +++--- .../contrib/notebook/common/notebookCommon.ts | 7 +--- 6 files changed, 63 insertions(+), 47 deletions(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index bf24ab9b655..a06d8165fab 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1507,9 +1507,9 @@ declare module 'vscode' { readonly mime: string; readonly value: unknown; - readonly metadata?: Record; + readonly metadata?: Record; - constructor(mime: string, value: unknown, metadata?: Record); + constructor(mime: string, value: unknown, metadata?: Record); } // @jrieken @@ -1517,7 +1517,11 @@ declare module 'vscode' { export class NotebookCellOutput { readonly id: string; readonly outputs: NotebookCellOutputItem[]; - constructor(outputs: NotebookCellOutputItem[], id?: string); + readonly metadata?: Record; + + constructor(outputs: NotebookCellOutputItem[], metadata?: Record); + + constructor(outputs: NotebookCellOutputItem[], id: string, metadata?: Record); } //#endregion diff --git a/src/vs/workbench/api/common/extHostNotebookDocument.ts b/src/vs/workbench/api/common/extHostNotebookDocument.ts index b20e4c9ed1e..4bd68b65686 100644 --- a/src/vs/workbench/api/common/extHostNotebookDocument.ts +++ b/src/vs/workbench/api/common/extHostNotebookDocument.ts @@ -47,7 +47,7 @@ export class ExtHostCell { private _onDidDispose = new Emitter(); readonly onDidDispose: Event = this._onDidDispose.event; - private _outputs: IOutputDto[]; + private _outputs: extHostTypes.NotebookCellOutput[]; private _metadata: extHostTypes.NotebookCellMetadata; readonly handle: number; @@ -64,7 +64,7 @@ export class ExtHostCell { this.handle = _cellData.handle; this.uri = URI.revive(_cellData.uri); this.cellKind = _cellData.cellKind; - this._outputs = _cellData.outputs; + this._outputs = _cellData.outputs.map(extHostTypeConverters.NotebookCellOutput.to); this._metadata = extHostTypeConverters.NotebookCellMetadata.to(_cellData.metadata ?? {}); } @@ -87,7 +87,7 @@ export class ExtHostCell { cellKind: extHostTypeConverters.NotebookCellKind.to(this._cellData.cellKind), document: data.document, get language() { return data!.document.languageId; }, - get outputs() { return that._outputs.map(extHostTypeConverters.NotebookCellOutput.to); }, + get outputs() { return that._outputs.slice(0); }, set outputs(_value) { throw new Error('Use WorkspaceEdit to update cell outputs.'); }, get metadata() { return that._metadata; }, set metadata(_value) { throw new Error('Use WorkspaceEdit to update cell metadata.'); }, @@ -97,17 +97,17 @@ export class ExtHostCell { } setOutputs(newOutputs: IOutputDto[]): void { - this._outputs = newOutputs; + this._outputs = newOutputs.map(extHostTypeConverters.NotebookCellOutput.to); } setOutputItems(outputId: string, append: boolean, newOutputItems: IOutputItemDto[]) { - const output = this._outputs.find(op => op.outputId === outputId); + const newItems = newOutputItems.map(extHostTypeConverters.NotebookCellOutputItem.to); + const output = this._outputs.find(op => op.id === outputId); if (output) { - if (append) { - output.outputs = [...output.outputs, ...newOutputItems]; - } else { - output.outputs = newOutputItems; + if (!append) { + output.outputs.length = 0; } + output.outputs.push(...newItems); } } diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 8b57657a364..039418367df 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -596,7 +596,7 @@ export namespace WorkspaceEdit { editType: notebooks.CellEditType.OutputItems, index: entry.index, outputId: entry.outputId, - items: entry.newOutputItems?.map(item => ({ mime: item.mime, value: item.value, metadata: item.metadata })) || [], + items: entry.newOutputItems?.map(NotebookCellOutputItem.from) || [], append: entry.append } }); @@ -1476,31 +1476,32 @@ export namespace NotebookCellData { } } +export namespace NotebookCellOutputItem { + export function from(item: types.NotebookCellOutputItem): notebooks.IOutputItemDto { + return { + mime: item.mime, + value: item.value, + metadata: item.metadata + }; + } + + export function to(item: notebooks.IOutputItemDto): types.NotebookCellOutputItem { + return new types.NotebookCellOutputItem(item.mime, item.value, item.metadata); + } +} + export namespace NotebookCellOutput { export function from(output: types.NotebookCellOutput): notebooks.IOutputDto { - - const data = Object.create(null); - const custom = Object.create(null); - - for (let item of output.outputs) { - data[item.mime] = item.value; - custom[item.mime] = item.metadata; - } - return { outputId: output.id, - outputs: (output.outputs || []).map(op => ({ - mime: op.mime, - value: op.value, - metadata: op.metadata - })) || [], - // metadata: isEmptyObject(custom) ? undefined : { custom } + outputs: output.outputs.map(NotebookCellOutputItem.from), + metadata: output.metadata }; } export function to(output: notebooks.IOutputDto): vscode.NotebookCellOutput { - const items: types.NotebookCellOutputItem[] = output.outputs.map(op => new types.NotebookCellOutputItem(op.mime, op.value, op.metadata)); - return new types.NotebookCellOutput(items, output.outputId); + const items = output.outputs.map(NotebookCellOutputItem.to); + return new types.NotebookCellOutput(items, output.outputId, output.metadata); } } diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index c815d8322af..7a2b4b9a1b9 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -703,8 +703,7 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit { } private _editNotebookCellOutput(uri: URI, index: number, append: boolean, outputs: vscode.NotebookCellOutput[], metadata: vscode.WorkspaceEditEntryMetadata | undefined): void { - let newOutputs: NotebookCellOutput[] = outputs; - this._edits.push({ _type: FileEditType.CellOutput, metadata, uri, index, append, newOutputs, newMetadata: undefined }); + this._edits.push({ _type: FileEditType.CellOutput, metadata, uri, index, append, newOutputs: outputs, newMetadata: undefined }); } replaceNotebookCellMetadata(uri: URI, index: number, cellMetadata: vscode.NotebookCellMetadata, metadata?: vscode.WorkspaceEditEntryMetadata): void { @@ -2993,15 +2992,30 @@ export class NotebookCellOutputItem { constructor( readonly mime: string, readonly value: unknown, // JSON'able - readonly metadata?: any + readonly metadata?: Record ) { } } export class NotebookCellOutput { + + readonly outputs: NotebookCellOutputItem[]; + readonly id: string; + readonly metadata?: Record; + constructor( - readonly outputs: NotebookCellOutputItem[], - readonly id: string = generateUuid() - ) { } + outputs: NotebookCellOutputItem[], + idOrMetadata?: string | Record, + metadata?: Record + ) { + this.outputs = outputs; + if (typeof idOrMetadata === 'string') { + this.id = idOrMetadata; + this.metadata = metadata; + } else { + this.id = generateUuid(); + this.metadata = idOrMetadata ?? metadata; + } + } } export enum NotebookCellKind { diff --git a/src/vs/workbench/contrib/notebook/common/model/notebookCellOutputTextModel.ts b/src/vs/workbench/contrib/notebook/common/model/notebookCellOutputTextModel.ts index 0172d6a1f2d..aa05e729203 100644 --- a/src/vs/workbench/contrib/notebook/common/model/notebookCellOutputTextModel.ts +++ b/src/vs/workbench/contrib/notebook/common/model/notebookCellOutputTextModel.ts @@ -16,9 +16,11 @@ export class NotebookCellOutputTextModel extends Disposable implements ICellOutp get outputs() { return this._rawOutput.outputs || []; } - // get metadata(): NotebookCellOutputMetadata | undefined { - // return this._rawOutput.metadata; - // } + + get metadata(): Record | undefined { + return this._rawOutput.metadata; + } + get outputId(): string { return this._rawOutput.outputId; } @@ -47,10 +49,10 @@ export class NotebookCellOutputTextModel extends Disposable implements ICellOutp this._onDidChangeData.fire(); } - toJSON() { + toJSON(): IOutputDto { return { // data: this._data, - // metadata: this._rawOutput.metadata, + metadata: this._rawOutput.metadata, outputs: this._rawOutput.outputs, outputId: this._rawOutput.outputId }; diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index be7d26f468d..8196d8ac5f2 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -159,13 +159,8 @@ export interface IOutputItemDto { export interface IOutputDto { outputs: IOutputItemDto[]; - /** - * { mime_type: value } - */ - // data: { [key: string]: unknown; } - - // metadata?: NotebookCellOutputMetadata; outputId: string; + metadata?: Record; } export interface ICellOutput { From 44dbd182557ee8c164f3917a2f9dc09a37ff623c Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Wed, 17 Feb 2021 11:47:52 +0100 Subject: [PATCH 246/325] Wait for tree to be registered before disposing This fixes the tree view rpc test Fixes #116776 --- src/vs/workbench/api/browser/mainThreadTreeViews.ts | 2 +- src/vs/workbench/api/common/extHost.protocol.ts | 2 +- src/vs/workbench/api/common/extHostTreeViews.ts | 7 ++++--- src/vs/workbench/test/browser/api/extHostTreeViews.test.ts | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadTreeViews.ts b/src/vs/workbench/api/browser/mainThreadTreeViews.ts index cfe9d842e8d..40b6794bfae 100644 --- a/src/vs/workbench/api/browser/mainThreadTreeViews.ts +++ b/src/vs/workbench/api/browser/mainThreadTreeViews.ts @@ -31,7 +31,7 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTreeViews); } - $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean }): void { + async $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean }): Promise { this.logService.trace('MainThreadTreeViews#$registerTreeViewDataProvider', treeViewId, options); this.extensionService.whenInstalledExtensionsRegistered().then(() => { diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index fdb63d9c2d2..2e330fd4ee5 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -285,7 +285,7 @@ export interface MainThreadTextEditorsShape extends IDisposable { } export interface MainThreadTreeViewsShape extends IDisposable { - $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean; }): void; + $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean; }): Promise; $refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem; }): Promise; $reveal(treeViewId: string, itemInfo: { item: ITreeItem, parentChain: ITreeItem[] } | undefined, options: IRevealOptions): Promise; $setMessage(treeViewId: string, message: string): void; diff --git a/src/vs/workbench/api/common/extHostTreeViews.ts b/src/vs/workbench/api/common/extHostTreeViews.ts index ca1914d2e38..df51908e74a 100644 --- a/src/vs/workbench/api/common/extHostTreeViews.ts +++ b/src/vs/workbench/api/common/extHostTreeViews.ts @@ -84,7 +84,7 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape { if (!options || !options.treeDataProvider) { throw new Error('Options with treeDataProvider is mandatory'); } - + const registerPromise = this._proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany }); const treeView = this.createExtHostTreeView(viewId, options, extension); return { get onDidCollapseElement() { return treeView.onDidCollapseElement; }, @@ -110,7 +110,9 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape { reveal: (element: T, options?: IRevealOptions): Promise => { return treeView.reveal(element, options); }, - dispose: () => { + dispose: async () => { + // Wait for the registration promise to finish before doing the dispose. + await registerPromise; this.treeViews.delete(viewId); treeView.dispose(); } @@ -240,7 +242,6 @@ class ExtHostTreeView extends Disposable { } } this.dataProvider = options.treeDataProvider; - this.proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany }); if (this.dataProvider.onDidChangeTreeData) { this._register(this.dataProvider.onDidChangeTreeData(element => this._onDidChangeData.fire({ message: false, element }))); } diff --git a/src/vs/workbench/test/browser/api/extHostTreeViews.test.ts b/src/vs/workbench/test/browser/api/extHostTreeViews.test.ts index 22f2eeef016..134e347dd65 100644 --- a/src/vs/workbench/test/browser/api/extHostTreeViews.test.ts +++ b/src/vs/workbench/test/browser/api/extHostTreeViews.test.ts @@ -26,7 +26,7 @@ suite('ExtHostTreeView', function () { onRefresh = new Emitter<{ [treeItemHandle: string]: ITreeItem }>(); - $registerTreeViewDataProvider(treeViewId: string): void { + async $registerTreeViewDataProvider(treeViewId: string): Promise { } $refresh(viewId: string, itemsToRefresh: { [treeItemHandle: string]: ITreeItem }): Promise { From 13070015bddbca61ad566d1abb8aa3ea95edf9cb Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 17 Feb 2021 11:52:11 +0100 Subject: [PATCH 247/325] expose context key info command, add first version of completion item provider for package.json and keybindings.json files, https://github.com/microsoft/vscode/issues/9303 --- .../src/configurationEditingMain.ts | 40 +++++++++++++++++++ .../contextkey/browser/contextKeyService.ts | 12 ++++++ .../platform/contextkey/common/contextkey.ts | 4 +- 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/extensions/configuration-editing/src/configurationEditingMain.ts b/extensions/configuration-editing/src/configurationEditingMain.ts index a3ef34f3d83..f4c2ab34174 100644 --- a/extensions/configuration-editing/src/configurationEditingMain.ts +++ b/extensions/configuration-editing/src/configurationEditingMain.ts @@ -22,6 +22,9 @@ export function activate(context: vscode.ExtensionContext): void { // task.json variable suggestions context.subscriptions.push(registerVariableCompletions('**/tasks.json')); + + // keybindings.json/package.json context key suggestions + context.subscriptions.push(registerContextKeyCompletions()); } function registerSettingsCompletions(): vscode.Disposable { @@ -136,3 +139,40 @@ vscode.languages.registerDocumentSymbolProvider({ pattern: '**/launch.json', lan return result; } }, { label: 'Launch Targets' }); + +function registerContextKeyCompletions(): vscode.Disposable { + type ContextKeyInfo = { key: string, type?: string, description?: string }; + return vscode.languages.registerCompletionItemProvider( + [{ language: 'json', pattern: '**/package.json' }, { language: 'jsonc', pattern: '**/keybindings.json' }], + { + async provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken) { + + const replacing = document.getWordRangeAtPosition(position, /[\w.-\d]/); + const inserting = replacing?.with(undefined, position); + if (!replacing || !inserting) { + return; + } + + const location = getLocation(document.getText(), document.offsetAt(position)); + if (!location.matches(['*', 'when']) && !location.matches(['contributes', 'menus', '*', '*', 'when'])) { + return; + } + + const data = await vscode.commands.executeCommand('getContextKeyInfo'); + if (token.isCancellationRequested || !data) { + return; + } + + const result = new vscode.CompletionList(); + for (const item of data) { + const completion = new vscode.CompletionItem(item.key, vscode.CompletionItemKind.Constant); + completion.detail = item.type; + completion.range = { replacing, inserting }; + completion.documentation = item.description; + result.items.push(completion); + } + return result; + } + } + ); +} diff --git a/src/vs/platform/contextkey/browser/contextKeyService.ts b/src/vs/platform/contextkey/browser/contextKeyService.ts index 00e2bde4875..e40016315b3 100644 --- a/src/vs/platform/contextkey/browser/contextKeyService.ts +++ b/src/vs/platform/contextkey/browser/contextKeyService.ts @@ -8,6 +8,7 @@ import { Iterable } from 'vs/base/common/iterator'; import { IDisposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; import { TernarySearchTree } from 'vs/base/common/map'; import { distinct } from 'vs/base/common/objects'; +import { localize } from 'vs/nls'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContext, IContextKey, IContextKeyChangeEvent, IContextKeyService, IContextKeyServiceTarget, IReadableSet, SET_CONTEXT_COMMAND_ID, ContextKeyExpression, RawContextKey, ContextKeyInfo } from 'vs/platform/contextkey/common/contextkey'; @@ -578,6 +579,17 @@ CommandsRegistry.registerCommand(SET_CONTEXT_COMMAND_ID, function (accessor, con accessor.get(IContextKeyService).createKey(String(contextKey), contextValue); }); +CommandsRegistry.registerCommand({ + id: 'getContextKeyInfo', + handler() { + return [...RawContextKey.all()].sort((a, b) => a.key.localeCompare(b.key)); + }, + description: { + description: localize('getContextKeyInfo', "A command that returns information about context keys"), + args: [] + } +}); + CommandsRegistry.registerCommand('_generateContextKeyInfo', function () { const result: ContextKeyInfo[] = []; const seen = new Set(); diff --git a/src/vs/platform/contextkey/common/contextkey.ts b/src/vs/platform/contextkey/common/contextkey.ts index 6ecb8a5dc76..af2326a7565 100644 --- a/src/vs/platform/contextkey/common/contextkey.ts +++ b/src/vs/platform/contextkey/common/contextkey.ts @@ -1259,7 +1259,7 @@ export class ContextKeyOrExpr implements IContextKeyExpression { export interface ContextKeyInfo { readonly key: string; - readonly type: string; + readonly type?: string; readonly description?: string; } @@ -1281,7 +1281,7 @@ export class RawContextKey extends ContextKeyDefinedExpr { if (typeof metaOrHide === 'object') { RawContextKey._info.push({ ...metaOrHide, key }); } else if (metaOrHide !== true) { - RawContextKey._info.push({ key, description: metaOrHide, type: typeof defaultValue }); + RawContextKey._info.push({ key, description: metaOrHide, type: defaultValue !== null && defaultValue !== undefined ? typeof defaultValue : undefined }); } } From 678acbe536491d9dccf1b983291fe61b29e26fcc Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 17 Feb 2021 13:16:28 +0100 Subject: [PATCH 248/325] outputs in notebooks --- .vscode/notebooks/api.github-issues | 1305 ++++++++++++++++++++++++++- 1 file changed, 1299 insertions(+), 6 deletions(-) diff --git a/.vscode/notebooks/api.github-issues b/.vscode/notebooks/api.github-issues index 71fd646776f..c0154336692 100644 --- a/.vscode/notebooks/api.github-issues +++ b/.vscode/notebooks/api.github-issues @@ -3,36 +3,1329 @@ "kind": 1, "language": "markdown", "value": "#### Config", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 2, "language": "github-issues", "value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"February 2021\"", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 1, "language": "markdown", "value": "### Finalization", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 2, "language": "github-issues", "value": "$repo $milestone label:api-finalization", - "editable": true + "editable": true, + "outputs": [ + { + "mime": "text/markdown", + "value": "- [#88309](https://github.com/microsoft/vscode/issues/88309 \"Authentication Provider API\") Authentication Provider API [api-finalization, authentication, feature-request, settings-sync]- [@RMacfarlane](https://github.com/RMacfarlane \"Issue 88309 is assigned to RMacfarlane\")\n\n" + }, + { + "mime": "x-application/github-issues", + "value": [ + { + "url": "https://api.github.com/repos/microsoft/vscode/issues/88309", + "repository_url": "https://api.github.com/repos/microsoft/vscode", + "labels_url": "https://api.github.com/repos/microsoft/vscode/issues/88309/labels{/name}", + "comments_url": "https://api.github.com/repos/microsoft/vscode/issues/88309/comments", + "events_url": "https://api.github.com/repos/microsoft/vscode/issues/88309/events", + "html_url": "https://github.com/microsoft/vscode/issues/88309", + "id": 547141160, + "node_id": "MDU6SXNzdWU1NDcxNDExNjA=", + "number": 88309, + "title": "Authentication Provider API", + "user": { + "login": "RMacfarlane", + "id": 3672607, + "node_id": "MDQ6VXNlcjM2NzI2MDc=", + "avatar_url": "https://avatars.githubusercontent.com/u/3672607?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/RMacfarlane", + "html_url": "https://github.com/RMacfarlane", + "followers_url": "https://api.github.com/users/RMacfarlane/followers", + "following_url": "https://api.github.com/users/RMacfarlane/following{/other_user}", + "gists_url": "https://api.github.com/users/RMacfarlane/gists{/gist_id}", + "starred_url": "https://api.github.com/users/RMacfarlane/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/RMacfarlane/subscriptions", + "organizations_url": "https://api.github.com/users/RMacfarlane/orgs", + "repos_url": "https://api.github.com/users/RMacfarlane/repos", + "events_url": "https://api.github.com/users/RMacfarlane/events{/privacy}", + "received_events_url": "https://api.github.com/users/RMacfarlane/received_events", + "type": "User", + "site_admin": false + }, + "labels": [ + { + "id": 974714207, + "node_id": "MDU6TGFiZWw5NzQ3MTQyMDc=", + "url": "https://api.github.com/repos/microsoft/vscode/labels/api-finalization", + "name": "api-finalization", + "color": "c5def5", + "default": false, + "description": "" + }, + { + "id": 1702048079, + "node_id": "MDU6TGFiZWwxNzAyMDQ4MDc5", + "url": "https://api.github.com/repos/microsoft/vscode/labels/authentication", + "name": "authentication", + "color": "c5def5", + "default": false, + "description": "Authentication issues" + }, + { + "id": 272689392, + "node_id": "MDU6TGFiZWwyNzI2ODkzOTI=", + "url": "https://api.github.com/repos/microsoft/vscode/labels/feature-request", + "name": "feature-request", + "color": "dcdcdc", + "default": false, + "description": "Request for new features or functionality" + }, + { + "id": 1684021718, + "node_id": "MDU6TGFiZWwxNjg0MDIxNzE4", + "url": "https://api.github.com/repos/microsoft/vscode/labels/settings-sync", + "name": "settings-sync", + "color": "1d76db", + "default": false, + "description": "" + } + ], + "state": "open", + "locked": false, + "assignee": { + "login": "RMacfarlane", + "id": 3672607, + "node_id": "MDQ6VXNlcjM2NzI2MDc=", + "avatar_url": "https://avatars.githubusercontent.com/u/3672607?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/RMacfarlane", + "html_url": "https://github.com/RMacfarlane", + "followers_url": "https://api.github.com/users/RMacfarlane/followers", + "following_url": "https://api.github.com/users/RMacfarlane/following{/other_user}", + "gists_url": "https://api.github.com/users/RMacfarlane/gists{/gist_id}", + "starred_url": "https://api.github.com/users/RMacfarlane/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/RMacfarlane/subscriptions", + "organizations_url": "https://api.github.com/users/RMacfarlane/orgs", + "repos_url": "https://api.github.com/users/RMacfarlane/repos", + "events_url": "https://api.github.com/users/RMacfarlane/events{/privacy}", + "received_events_url": "https://api.github.com/users/RMacfarlane/received_events", + "type": "User", + "site_admin": false + }, + "assignees": [ + { + "login": "RMacfarlane", + "id": 3672607, + "node_id": "MDQ6VXNlcjM2NzI2MDc=", + "avatar_url": "https://avatars.githubusercontent.com/u/3672607?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/RMacfarlane", + "html_url": "https://github.com/RMacfarlane", + "followers_url": "https://api.github.com/users/RMacfarlane/followers", + "following_url": "https://api.github.com/users/RMacfarlane/following{/other_user}", + "gists_url": "https://api.github.com/users/RMacfarlane/gists{/gist_id}", + "starred_url": "https://api.github.com/users/RMacfarlane/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/RMacfarlane/subscriptions", + "organizations_url": "https://api.github.com/users/RMacfarlane/orgs", + "repos_url": "https://api.github.com/users/RMacfarlane/repos", + "events_url": "https://api.github.com/users/RMacfarlane/events{/privacy}", + "received_events_url": "https://api.github.com/users/RMacfarlane/received_events", + "type": "User", + "site_admin": false + } + ], + "milestone": { + "url": "https://api.github.com/repos/microsoft/vscode/milestones/142", + "html_url": "https://github.com/microsoft/vscode/milestone/142", + "labels_url": "https://api.github.com/repos/microsoft/vscode/milestones/142/labels", + "id": 6286096, + "node_id": "MDk6TWlsZXN0b25lNjI4NjA5Ng==", + "number": 142, + "title": "February 2021", + "description": "", + "creator": { + "login": "Tyriar", + "id": 2193314, + "node_id": "MDQ6VXNlcjIxOTMzMTQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/2193314?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/Tyriar", + "html_url": "https://github.com/Tyriar", + "followers_url": "https://api.github.com/users/Tyriar/followers", + "following_url": "https://api.github.com/users/Tyriar/following{/other_user}", + "gists_url": "https://api.github.com/users/Tyriar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/Tyriar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/Tyriar/subscriptions", + "organizations_url": "https://api.github.com/users/Tyriar/orgs", + "repos_url": "https://api.github.com/users/Tyriar/repos", + "events_url": "https://api.github.com/users/Tyriar/events{/privacy}", + "received_events_url": "https://api.github.com/users/Tyriar/received_events", + "type": "User", + "site_admin": false + }, + "open_issues": 232, + "closed_issues": 300, + "state": "open", + "created_at": "2021-01-07T18:23:10Z", + "updated_at": "2021-02-17T10:48:47Z", + "due_on": null, + "closed_at": null + }, + "comments": 23, + "created_at": "2020-01-08T22:31:35Z", + "updated_at": "2021-02-10T20:41:11Z", + "closed_at": null, + "author_association": "MEMBER", + "active_lock_reason": null, + "body": "### Problem\r\n\r\nThere are currently some extensions that attempt to provide authentication abilities that can be reused by other extensions. (An example being the Azure Account extension). Now that we've begun working on login for settings sync, it's worth revisiting if authentication should be a first-class concept in VS Code. By exposing an API to contribute an authentication flow\r\n\r\n- the core of VSCode can potentially leverage authentication\r\n- other extensions can leverage authentication\r\n- UI for account management could be centralized\r\n\r\n### Proposal\r\n\r\nI propose introducing a concept of an \"AuthenticationProvider\". Such a provider implements methods for logging in and logging out of a specified account, and exposes a list of accounts that are currently available with an event listener for changes to these. This abstracts away refreshing tokens from consumers - the AuthenticationProvider extension can manage refreshing in the background and fire an event when the accessToken has been changed.\r\n\r\n```ts\r\nexport interface Account {\r\n\treadonly id: string;\r\n\treadonly accessToken: string;\r\n\treadonly displayName: string;\r\n}\r\n\r\nexport interface AuthenticationProvider {\r\n\treadonly id: string; // perhaps \"type\"? Would be something like \"GitHub\", \"MSA\", etc.\r\n\treadonly displayName: string;\r\n\r\n\taccounts: ReadonlyArray;\r\n\tonDidChangeAccounts: Event>;\r\n\r\n\tlogin(): Promise;\r\n\tlogout(accountId: string): Promise;\r\n}\r\n\r\nexport namespace authentication {\r\n\texport function registerAuthenticationProvider(provider: AuthenticationProvider): Disposable;\r\n\texport const authenticationProviders: ReadonlyArray;\r\n}\r\n```\r\n\r\nConsumers would need to know the id of the provider they're looking for. For example, the settings sync code would look for an \"MSA\" provider since this is what the setting sync backend currently needs.\r\n\r\nSince the authentication provider extension would be activated in each VS Code window, the extension would be responsible for synchronizing state across instances. By default, such extensions would have [\"ui\", \"workspace\"] extensionKind, so that they can store and read credentials on the local machine in both the desktop and web case.", + "performed_via_github_app": null, + "score": 1 + } + ] + } + ] }, { "kind": 1, "language": "markdown", "value": "### Proposals", - "editable": true + "editable": true, + "outputs": [] }, { "kind": 2, "language": "github-issues", "value": "$repo $milestone is:open label:api-proposal ", - "editable": true + "editable": true, + "outputs": [ + { + "mime": "text/markdown", + "value": "- [#115631](https://github.com/microsoft/vscode/issues/115631 \"Provide a way for custom editors to process untitled files without relying on textDocument\") Provide a way for custom editors to process untitled files without relying on textDocument [api-proposal, custom-editors, notebook]- [@lramos15](https://github.com/lramos15 \"Issue 115631 is assigned to lramos15\")\n\n- [#115626](https://github.com/microsoft/vscode/issues/115626 \"Microsoft Auth Provider should support overriding client id and tenant id\") Microsoft Auth Provider should support overriding client id and tenant id [api-proposal, authentication]- [@TylerLeonhardt](https://github.com/TylerLeonhardt \"Issue 115626 is assigned to TylerLeonhardt\")\n\n- [#115616](https://github.com/microsoft/vscode/issues/115616 \"Provide extension API to exclude ports from forwarding\") Provide extension API to exclude ports from forwarding [api, api-proposal, feature-request, remote-explorer]\n- [#114123](https://github.com/microsoft/vscode/issues/114123 \"Resolve the conflict run button in editor context menu\") Resolve the conflict run button in editor context menu [api-proposal, feature-request, menus]- [@jrieken](https://github.com/jrieken \"Issue 114123 is assigned to jrieken\")\n\n- [#109277](https://github.com/microsoft/vscode/issues/109277 \"Let extensions hook into url opening\") Let extensions hook into url opening [api, api-proposal, under-discussion]- [@mjbvz](https://github.com/mjbvz \"Issue 109277 is assigned to mjbvz\")\n\n- [#107467](https://github.com/microsoft/vscode/issues/107467 \"Testing in VS Code\") Testing in VS Code [api-proposal, plan-item, under-discussion]- [@connor4312](https://github.com/connor4312 \"Issue 107467 is assigned to connor4312\")\n\n- [#105690](https://github.com/microsoft/vscode/issues/105690 \"Extension API for Inline Values\") Extension API for Inline Values [api, api-proposal, debug, feature-request]- [@weinand](https://github.com/weinand \"Issue 105690 is assigned to weinand\")\n\n" + }, + { + "mime": "x-application/github-issues", + "value": [ + { + "url": "https://api.github.com/repos/microsoft/vscode/issues/115631", + "repository_url": "https://api.github.com/repos/microsoft/vscode", + "labels_url": "https://api.github.com/repos/microsoft/vscode/issues/115631/labels{/name}", + "comments_url": "https://api.github.com/repos/microsoft/vscode/issues/115631/comments", + "events_url": "https://api.github.com/repos/microsoft/vscode/issues/115631/events", + "html_url": "https://github.com/microsoft/vscode/issues/115631", + "id": 799606785, + "node_id": "MDU6SXNzdWU3OTk2MDY3ODU=", + "number": 115631, + "title": "Provide a way for custom editors to process untitled files without relying on textDocument", + "user": { + "login": "lramos15", + "id": 4544166, + "node_id": "MDQ6VXNlcjQ1NDQxNjY=", + "avatar_url": "https://avatars.githubusercontent.com/u/4544166?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/lramos15", + "html_url": "https://github.com/lramos15", + "followers_url": "https://api.github.com/users/lramos15/followers", + "following_url": "https://api.github.com/users/lramos15/following{/other_user}", + "gists_url": "https://api.github.com/users/lramos15/gists{/gist_id}", + "starred_url": "https://api.github.com/users/lramos15/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/lramos15/subscriptions", + "organizations_url": "https://api.github.com/users/lramos15/orgs", + "repos_url": "https://api.github.com/users/lramos15/repos", + "events_url": "https://api.github.com/users/lramos15/events{/privacy}", + "received_events_url": "https://api.github.com/users/lramos15/received_events", + "type": "User", + "site_admin": false + }, + "labels": [ + { + "id": 869332220, + "node_id": "MDU6TGFiZWw4NjkzMzIyMjA=", + "url": "https://api.github.com/repos/microsoft/vscode/labels/api-proposal", + "name": "api-proposal", + "color": "c5def5", + "default": false, + "description": "" + }, + { + "id": 1713330180, + "node_id": "MDU6TGFiZWwxNzEzMzMwMTgw", + "url": "https://api.github.com/repos/microsoft/vscode/labels/custom-editors", + "name": "custom-editors", + "color": "c5def5", + "default": false, + "description": "Custom editor API (webview based editors)" + }, + { + "id": 1839857516, + "node_id": "MDU6TGFiZWwxODM5ODU3NTE2", + "url": "https://api.github.com/repos/microsoft/vscode/labels/notebook", + "name": "notebook", + "color": "c5def5", + "default": false, + "description": "" + } + ], + "state": "open", + "locked": false, + "assignee": { + "login": "lramos15", + "id": 4544166, + "node_id": "MDQ6VXNlcjQ1NDQxNjY=", + "avatar_url": "https://avatars.githubusercontent.com/u/4544166?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/lramos15", + "html_url": "https://github.com/lramos15", + "followers_url": "https://api.github.com/users/lramos15/followers", + "following_url": "https://api.github.com/users/lramos15/following{/other_user}", + "gists_url": "https://api.github.com/users/lramos15/gists{/gist_id}", + "starred_url": "https://api.github.com/users/lramos15/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/lramos15/subscriptions", + "organizations_url": "https://api.github.com/users/lramos15/orgs", + "repos_url": "https://api.github.com/users/lramos15/repos", + "events_url": "https://api.github.com/users/lramos15/events{/privacy}", + "received_events_url": "https://api.github.com/users/lramos15/received_events", + "type": "User", + "site_admin": false + }, + "assignees": [ + { + "login": "lramos15", + "id": 4544166, + "node_id": "MDQ6VXNlcjQ1NDQxNjY=", + "avatar_url": "https://avatars.githubusercontent.com/u/4544166?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/lramos15", + "html_url": "https://github.com/lramos15", + "followers_url": "https://api.github.com/users/lramos15/followers", + "following_url": "https://api.github.com/users/lramos15/following{/other_user}", + "gists_url": "https://api.github.com/users/lramos15/gists{/gist_id}", + "starred_url": "https://api.github.com/users/lramos15/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/lramos15/subscriptions", + "organizations_url": "https://api.github.com/users/lramos15/orgs", + "repos_url": "https://api.github.com/users/lramos15/repos", + "events_url": "https://api.github.com/users/lramos15/events{/privacy}", + "received_events_url": "https://api.github.com/users/lramos15/received_events", + "type": "User", + "site_admin": false + }, + { + "login": "mjbvz", + "id": 12821956, + "node_id": "MDQ6VXNlcjEyODIxOTU2", + "avatar_url": "https://avatars.githubusercontent.com/u/12821956?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/mjbvz", + "html_url": "https://github.com/mjbvz", + "followers_url": "https://api.github.com/users/mjbvz/followers", + "following_url": "https://api.github.com/users/mjbvz/following{/other_user}", + "gists_url": "https://api.github.com/users/mjbvz/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mjbvz/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mjbvz/subscriptions", + "organizations_url": "https://api.github.com/users/mjbvz/orgs", + "repos_url": "https://api.github.com/users/mjbvz/repos", + "events_url": "https://api.github.com/users/mjbvz/events{/privacy}", + "received_events_url": "https://api.github.com/users/mjbvz/received_events", + "type": "User", + "site_admin": false + } + ], + "milestone": { + "url": "https://api.github.com/repos/microsoft/vscode/milestones/142", + "html_url": "https://github.com/microsoft/vscode/milestone/142", + "labels_url": "https://api.github.com/repos/microsoft/vscode/milestones/142/labels", + "id": 6286096, + "node_id": "MDk6TWlsZXN0b25lNjI4NjA5Ng==", + "number": 142, + "title": "February 2021", + "description": "", + "creator": { + "login": "Tyriar", + "id": 2193314, + "node_id": "MDQ6VXNlcjIxOTMzMTQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/2193314?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/Tyriar", + "html_url": "https://github.com/Tyriar", + "followers_url": "https://api.github.com/users/Tyriar/followers", + "following_url": "https://api.github.com/users/Tyriar/following{/other_user}", + "gists_url": "https://api.github.com/users/Tyriar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/Tyriar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/Tyriar/subscriptions", + "organizations_url": "https://api.github.com/users/Tyriar/orgs", + "repos_url": "https://api.github.com/users/Tyriar/repos", + "events_url": "https://api.github.com/users/Tyriar/events{/privacy}", + "received_events_url": "https://api.github.com/users/Tyriar/received_events", + "type": "User", + "site_admin": false + }, + "open_issues": 232, + "closed_issues": 300, + "state": "open", + "created_at": "2021-01-07T18:23:10Z", + "updated_at": "2021-02-17T10:48:47Z", + "due_on": null, + "closed_at": null + }, + "comments": 1, + "created_at": "2021-02-02T19:29:05Z", + "updated_at": "2021-02-02T21:58:36Z", + "closed_at": null, + "author_association": "MEMBER", + "active_lock_reason": null, + "body": "Currently the \"Reopen with\" experience for untitled files and custom binary editors needs better support. See #114711. After discussion in the API call the best proposal seems to be placing the untitled file data in the OpenEditor / OpenNotebook context. There interface would be modified as shown:\r\n```ts\r\n\t/**\r\n\t * Additional information about the opening custom document.\r\n\t */\r\n\tinterface CustomDocumentOpenContext {\r\n\t\t/**\r\n\t\t * The id of the backup to restore the document from or `undefined` if there is no backup.\r\n\t\t *\r\n\t\t * If this is provided, your extension should restore the editor from the backup instead of reading the file\r\n\t\t * from the user's workspace.\r\n\t\t */\r\n\t\treadonly backupId?: string;\r\n\t\t/**\r\n\t\t * If the URI is an untitled file, this will be populated with the byte data of that file\r\n\t\t *\r\n\t\t * If this is provided, your extension should utilize this byte data rather than executing fs APIs on the URI passed in\r\n\t\t */\r\n\t\treadonly untitledDocumentData?: Uint8Array;\r\n\t}\r\n\r\n\tinterface NotebookDocumentOpenContext {\r\n\t\treadonly backupId?: string;\r\n\t\treadonly untitledDocumentData?: Uint8Array;\r\n\t}\r\n```\r\nThe extension other would then not be required to resolve the URI to a text document (which would have been disposed of). ", + "performed_via_github_app": null, + "score": 1 + }, + { + "url": "https://api.github.com/repos/microsoft/vscode/issues/115626", + "repository_url": "https://api.github.com/repos/microsoft/vscode", + "labels_url": "https://api.github.com/repos/microsoft/vscode/issues/115626/labels{/name}", + "comments_url": "https://api.github.com/repos/microsoft/vscode/issues/115626/comments", + "events_url": "https://api.github.com/repos/microsoft/vscode/issues/115626/events", + "html_url": "https://github.com/microsoft/vscode/issues/115626", + "id": 799566516, + "node_id": "MDU6SXNzdWU3OTk1NjY1MTY=", + "number": 115626, + "title": "Microsoft Auth Provider should support overriding client id and tenant id", + "user": { + "login": "TylerLeonhardt", + "id": 2644648, + "node_id": "MDQ6VXNlcjI2NDQ2NDg=", + "avatar_url": "https://avatars.githubusercontent.com/u/2644648?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/TylerLeonhardt", + "html_url": "https://github.com/TylerLeonhardt", + "followers_url": "https://api.github.com/users/TylerLeonhardt/followers", + "following_url": "https://api.github.com/users/TylerLeonhardt/following{/other_user}", + "gists_url": "https://api.github.com/users/TylerLeonhardt/gists{/gist_id}", + "starred_url": "https://api.github.com/users/TylerLeonhardt/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/TylerLeonhardt/subscriptions", + "organizations_url": "https://api.github.com/users/TylerLeonhardt/orgs", + "repos_url": "https://api.github.com/users/TylerLeonhardt/repos", + "events_url": "https://api.github.com/users/TylerLeonhardt/events{/privacy}", + "received_events_url": "https://api.github.com/users/TylerLeonhardt/received_events", + "type": "User", + "site_admin": false + }, + "labels": [ + { + "id": 869332220, + "node_id": "MDU6TGFiZWw4NjkzMzIyMjA=", + "url": "https://api.github.com/repos/microsoft/vscode/labels/api-proposal", + "name": "api-proposal", + "color": "c5def5", + "default": false, + "description": "" + }, + { + "id": 1702048079, + "node_id": "MDU6TGFiZWwxNzAyMDQ4MDc5", + "url": "https://api.github.com/repos/microsoft/vscode/labels/authentication", + "name": "authentication", + "color": "c5def5", + "default": false, + "description": "Authentication issues" + } + ], + "state": "open", + "locked": false, + "assignee": { + "login": "TylerLeonhardt", + "id": 2644648, + "node_id": "MDQ6VXNlcjI2NDQ2NDg=", + "avatar_url": "https://avatars.githubusercontent.com/u/2644648?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/TylerLeonhardt", + "html_url": "https://github.com/TylerLeonhardt", + "followers_url": "https://api.github.com/users/TylerLeonhardt/followers", + "following_url": "https://api.github.com/users/TylerLeonhardt/following{/other_user}", + "gists_url": "https://api.github.com/users/TylerLeonhardt/gists{/gist_id}", + "starred_url": "https://api.github.com/users/TylerLeonhardt/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/TylerLeonhardt/subscriptions", + "organizations_url": "https://api.github.com/users/TylerLeonhardt/orgs", + "repos_url": "https://api.github.com/users/TylerLeonhardt/repos", + "events_url": "https://api.github.com/users/TylerLeonhardt/events{/privacy}", + "received_events_url": "https://api.github.com/users/TylerLeonhardt/received_events", + "type": "User", + "site_admin": false + }, + "assignees": [ + { + "login": "TylerLeonhardt", + "id": 2644648, + "node_id": "MDQ6VXNlcjI2NDQ2NDg=", + "avatar_url": "https://avatars.githubusercontent.com/u/2644648?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/TylerLeonhardt", + "html_url": "https://github.com/TylerLeonhardt", + "followers_url": "https://api.github.com/users/TylerLeonhardt/followers", + "following_url": "https://api.github.com/users/TylerLeonhardt/following{/other_user}", + "gists_url": "https://api.github.com/users/TylerLeonhardt/gists{/gist_id}", + "starred_url": "https://api.github.com/users/TylerLeonhardt/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/TylerLeonhardt/subscriptions", + "organizations_url": "https://api.github.com/users/TylerLeonhardt/orgs", + "repos_url": "https://api.github.com/users/TylerLeonhardt/repos", + "events_url": "https://api.github.com/users/TylerLeonhardt/events{/privacy}", + "received_events_url": "https://api.github.com/users/TylerLeonhardt/received_events", + "type": "User", + "site_admin": false + }, + { + "login": "RMacfarlane", + "id": 3672607, + "node_id": "MDQ6VXNlcjM2NzI2MDc=", + "avatar_url": "https://avatars.githubusercontent.com/u/3672607?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/RMacfarlane", + "html_url": "https://github.com/RMacfarlane", + "followers_url": "https://api.github.com/users/RMacfarlane/followers", + "following_url": "https://api.github.com/users/RMacfarlane/following{/other_user}", + "gists_url": "https://api.github.com/users/RMacfarlane/gists{/gist_id}", + "starred_url": "https://api.github.com/users/RMacfarlane/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/RMacfarlane/subscriptions", + "organizations_url": "https://api.github.com/users/RMacfarlane/orgs", + "repos_url": "https://api.github.com/users/RMacfarlane/repos", + "events_url": "https://api.github.com/users/RMacfarlane/events{/privacy}", + "received_events_url": "https://api.github.com/users/RMacfarlane/received_events", + "type": "User", + "site_admin": false + } + ], + "milestone": { + "url": "https://api.github.com/repos/microsoft/vscode/milestones/142", + "html_url": "https://github.com/microsoft/vscode/milestone/142", + "labels_url": "https://api.github.com/repos/microsoft/vscode/milestones/142/labels", + "id": 6286096, + "node_id": "MDk6TWlsZXN0b25lNjI4NjA5Ng==", + "number": 142, + "title": "February 2021", + "description": "", + "creator": { + "login": "Tyriar", + "id": 2193314, + "node_id": "MDQ6VXNlcjIxOTMzMTQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/2193314?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/Tyriar", + "html_url": "https://github.com/Tyriar", + "followers_url": "https://api.github.com/users/Tyriar/followers", + "following_url": "https://api.github.com/users/Tyriar/following{/other_user}", + "gists_url": "https://api.github.com/users/Tyriar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/Tyriar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/Tyriar/subscriptions", + "organizations_url": "https://api.github.com/users/Tyriar/orgs", + "repos_url": "https://api.github.com/users/Tyriar/repos", + "events_url": "https://api.github.com/users/Tyriar/events{/privacy}", + "received_events_url": "https://api.github.com/users/Tyriar/received_events", + "type": "User", + "site_admin": false + }, + "open_issues": 232, + "closed_issues": 300, + "state": "open", + "created_at": "2021-01-07T18:23:10Z", + "updated_at": "2021-02-17T10:48:47Z", + "due_on": null, + "closed_at": null + }, + "comments": 0, + "created_at": "2021-02-02T18:42:12Z", + "updated_at": "2021-02-02T18:58:50Z", + "closed_at": null, + "author_association": "MEMBER", + "active_lock_reason": null, + "body": "\r\n\r\n\r\n\r\n\r\n\r\nThe Microsoft Auth Provider uses a specific AAD application with client id hardcoded here:\r\nhttps://github.com/microsoft/vscode/blob/582ea371c2bf785d88458dab95828387ad94a63d/extensions/microsoft-authentication/src/AADHelper.ts#L25-L26\r\n\r\nHowever, this application only has access to a handful of scopes, and to add _allowed_ scopes to this client id is a manual process (which for an external extension author means opening an issue here and then having one of us add that scope to the _allowed_ scopes for the application)\r\n\r\nAs an extension author, I should easily be able to create my own AAD application (in the Azure Portal for example) and use that client id instead of the one vscode uses so that I can have control over the scopes I care about and, if this exists, I can get telemetry when my client id is used.\r\n\r\nSince we have abstracted auth providers, I think it's fitting to be able to pass additional auth provider specific options down to an auth provider. For example, the Microsoft auth provider would take a client id and tenant that would replace the hard coded string above.\r\n\r\nProposal:\r\n\r\n```ts\r\n /**\r\n\t * Options to be used when getting an [AuthenticationSession](#AuthenticationSession) from an [AuthenticationProvider](#AuthenticationProvider).\r\n\t */\r\n\texport interface AuthenticationGetSessionOptions {\r\n\t\t/**\r\n\t\t * Whether login should be performed if there is no matching session.\r\n\t\t *\r\n\t\t * If true, a modal dialog will be shown asking the user to sign in. If false, a numbered badge will be shown\r\n\t\t * on the accounts activity bar icon. An entry for the extension will be added under the menu to sign in. This\r\n\t\t * allows quietly prompting the user to sign in.\r\n\t\t *\r\n\t\t * Defaults to false.\r\n\t\t */\r\n\t\tcreateIfNone?: boolean;\r\n\r\n\t\t/**\r\n\t\t * Whether the existing user session preference should be cleared.\r\n\t\t *\r\n\t\t * For authentication providers that support being signed into multiple accounts at once, the user will be\r\n\t\t * prompted to select an account to use when [getSession](#authentication.getSession) is called. This preference\r\n\t\t * is remembered until [getSession](#authentication.getSession) is called with this flag.\r\n\t\t *\r\n\t\t * Defaults to false.\r\n\t\t */\r\n\t\tclearSessionPreference?: boolean;\r\n\r\n\t\t/*************/\r\n\t\t/*** NEW ***/\r\n\t\t/*************/\r\n /**\r\n * Provider specific options for getting this session (i.e. client id, tenant)\r\n */\r\n\t\tproviderOptions?: { [key: string]: any; }\r\n\t}\r\n```\r\n\r\nThe Auth Provider would then need to be responsible for deciding if it already has created a session with these options or if it needs to create a new session based on these options.", + "performed_via_github_app": null, + "score": 1 + }, + { + "url": "https://api.github.com/repos/microsoft/vscode/issues/115616", + "repository_url": "https://api.github.com/repos/microsoft/vscode", + "labels_url": "https://api.github.com/repos/microsoft/vscode/issues/115616/labels{/name}", + "comments_url": "https://api.github.com/repos/microsoft/vscode/issues/115616/comments", + "events_url": "https://api.github.com/repos/microsoft/vscode/issues/115616/events", + "html_url": "https://github.com/microsoft/vscode/issues/115616", + "id": 799392757, + "node_id": "MDU6SXNzdWU3OTkzOTI3NTc=", + "number": 115616, + "title": "Provide extension API to exclude ports from forwarding", + "user": { + "login": "alexr00", + "id": 38270282, + "node_id": "MDQ6VXNlcjM4MjcwMjgy", + "avatar_url": "https://avatars.githubusercontent.com/u/38270282?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/alexr00", + "html_url": "https://github.com/alexr00", + "followers_url": "https://api.github.com/users/alexr00/followers", + "following_url": "https://api.github.com/users/alexr00/following{/other_user}", + "gists_url": "https://api.github.com/users/alexr00/gists{/gist_id}", + "starred_url": "https://api.github.com/users/alexr00/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/alexr00/subscriptions", + "organizations_url": "https://api.github.com/users/alexr00/orgs", + "repos_url": "https://api.github.com/users/alexr00/repos", + "events_url": "https://api.github.com/users/alexr00/events{/privacy}", + "received_events_url": "https://api.github.com/users/alexr00/received_events", + "type": "User", + "site_admin": false + }, + "labels": [ + { + "id": 290465400, + "node_id": "MDU6TGFiZWwyOTA0NjU0MDA=", + "url": "https://api.github.com/repos/microsoft/vscode/labels/api", + "name": "api", + "color": "1d76db", + "default": false, + "description": "" + }, + { + "id": 869332220, + "node_id": "MDU6TGFiZWw4NjkzMzIyMjA=", + "url": "https://api.github.com/repos/microsoft/vscode/labels/api-proposal", + "name": "api-proposal", + "color": "c5def5", + "default": false, + "description": "" + }, + { + "id": 272689392, + "node_id": "MDU6TGFiZWwyNzI2ODkzOTI=", + "url": "https://api.github.com/repos/microsoft/vscode/labels/feature-request", + "name": "feature-request", + "color": "dcdcdc", + "default": false, + "description": "Request for new features or functionality" + }, + { + "id": 1772775110, + "node_id": "MDU6TGFiZWwxNzcyNzc1MTEw", + "url": "https://api.github.com/repos/microsoft/vscode/labels/remote-explorer", + "name": "remote-explorer", + "color": "1d76db", + "default": false, + "description": "Remote explorer view" + } + ], + "state": "open", + "locked": false, + "assignee": null, + "assignees": [ + { + "login": "alexr00", + "id": 38270282, + "node_id": "MDQ6VXNlcjM4MjcwMjgy", + "avatar_url": "https://avatars.githubusercontent.com/u/38270282?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/alexr00", + "html_url": "https://github.com/alexr00", + "followers_url": "https://api.github.com/users/alexr00/followers", + "following_url": "https://api.github.com/users/alexr00/following{/other_user}", + "gists_url": "https://api.github.com/users/alexr00/gists{/gist_id}", + "starred_url": "https://api.github.com/users/alexr00/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/alexr00/subscriptions", + "organizations_url": "https://api.github.com/users/alexr00/orgs", + "repos_url": "https://api.github.com/users/alexr00/repos", + "events_url": "https://api.github.com/users/alexr00/events{/privacy}", + "received_events_url": "https://api.github.com/users/alexr00/received_events", + "type": "User", + "site_admin": false + } + ], + "milestone": { + "url": "https://api.github.com/repos/microsoft/vscode/milestones/142", + "html_url": "https://github.com/microsoft/vscode/milestone/142", + "labels_url": "https://api.github.com/repos/microsoft/vscode/milestones/142/labels", + "id": 6286096, + "node_id": "MDk6TWlsZXN0b25lNjI4NjA5Ng==", + "number": 142, + "title": "February 2021", + "description": "", + "creator": { + "login": "Tyriar", + "id": 2193314, + "node_id": "MDQ6VXNlcjIxOTMzMTQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/2193314?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/Tyriar", + "html_url": "https://github.com/Tyriar", + "followers_url": "https://api.github.com/users/Tyriar/followers", + "following_url": "https://api.github.com/users/Tyriar/following{/other_user}", + "gists_url": "https://api.github.com/users/Tyriar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/Tyriar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/Tyriar/subscriptions", + "organizations_url": "https://api.github.com/users/Tyriar/orgs", + "repos_url": "https://api.github.com/users/Tyriar/repos", + "events_url": "https://api.github.com/users/Tyriar/events{/privacy}", + "received_events_url": "https://api.github.com/users/Tyriar/received_events", + "type": "User", + "site_admin": false + }, + "open_issues": 232, + "closed_issues": 300, + "state": "open", + "created_at": "2021-01-07T18:23:10Z", + "updated_at": "2021-02-17T10:48:47Z", + "due_on": null, + "closed_at": null + }, + "comments": 15, + "created_at": "2021-02-02T15:37:45Z", + "updated_at": "2021-02-12T16:08:10Z", + "closed_at": null, + "author_association": "MEMBER", + "active_lock_reason": null, + "body": "From @weinand:\r\nToday the tunneling service blindly forwards all communication ports.\r\nThis includes ports that are used for debugging (even if our remote debugging feature does not need these ports to be forwarded).\r\nThis is confusing for users because they see ports that they are not really interested in.\r\n\r\nI propose to add extension API so that individual ports or port ranges can be excluded from forwarding.\r\nDebug extensions could use this API.\r\n\r\n", + "performed_via_github_app": null, + "score": 1 + }, + { + "url": "https://api.github.com/repos/microsoft/vscode/issues/114123", + "repository_url": "https://api.github.com/repos/microsoft/vscode", + "labels_url": "https://api.github.com/repos/microsoft/vscode/issues/114123/labels{/name}", + "comments_url": "https://api.github.com/repos/microsoft/vscode/issues/114123/comments", + "events_url": "https://api.github.com/repos/microsoft/vscode/issues/114123/events", + "html_url": "https://github.com/microsoft/vscode/issues/114123", + "id": 783094648, + "node_id": "MDU6SXNzdWU3ODMwOTQ2NDg=", + "number": 114123, + "title": "Resolve the conflict run button in editor context menu", + "user": { + "login": "jdneo", + "id": 6193897, + "node_id": "MDQ6VXNlcjYxOTM4OTc=", + "avatar_url": "https://avatars.githubusercontent.com/u/6193897?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/jdneo", + "html_url": "https://github.com/jdneo", + "followers_url": "https://api.github.com/users/jdneo/followers", + "following_url": "https://api.github.com/users/jdneo/following{/other_user}", + "gists_url": "https://api.github.com/users/jdneo/gists{/gist_id}", + "starred_url": "https://api.github.com/users/jdneo/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/jdneo/subscriptions", + "organizations_url": "https://api.github.com/users/jdneo/orgs", + "repos_url": "https://api.github.com/users/jdneo/repos", + "events_url": "https://api.github.com/users/jdneo/events{/privacy}", + "received_events_url": "https://api.github.com/users/jdneo/received_events", + "type": "User", + "site_admin": false + }, + "labels": [ + { + "id": 869332220, + "node_id": "MDU6TGFiZWw4NjkzMzIyMjA=", + "url": "https://api.github.com/repos/microsoft/vscode/labels/api-proposal", + "name": "api-proposal", + "color": "c5def5", + "default": false, + "description": "" + }, + { + "id": 272689392, + "node_id": "MDU6TGFiZWwyNzI2ODkzOTI=", + "url": "https://api.github.com/repos/microsoft/vscode/labels/feature-request", + "name": "feature-request", + "color": "dcdcdc", + "default": false, + "description": "Request for new features or functionality" + }, + { + "id": 795791582, + "node_id": "MDU6TGFiZWw3OTU3OTE1ODI=", + "url": "https://api.github.com/repos/microsoft/vscode/labels/menus", + "name": "menus", + "color": "1d76db", + "default": false, + "description": "Menu items and widget issues" + } + ], + "state": "open", + "locked": false, + "assignee": { + "login": "jrieken", + "id": 1794099, + "node_id": "MDQ6VXNlcjE3OTQwOTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/1794099?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/jrieken", + "html_url": "https://github.com/jrieken", + "followers_url": "https://api.github.com/users/jrieken/followers", + "following_url": "https://api.github.com/users/jrieken/following{/other_user}", + "gists_url": "https://api.github.com/users/jrieken/gists{/gist_id}", + "starred_url": "https://api.github.com/users/jrieken/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/jrieken/subscriptions", + "organizations_url": "https://api.github.com/users/jrieken/orgs", + "repos_url": "https://api.github.com/users/jrieken/repos", + "events_url": "https://api.github.com/users/jrieken/events{/privacy}", + "received_events_url": "https://api.github.com/users/jrieken/received_events", + "type": "User", + "site_admin": false + }, + "assignees": [ + { + "login": "jrieken", + "id": 1794099, + "node_id": "MDQ6VXNlcjE3OTQwOTk=", + "avatar_url": "https://avatars.githubusercontent.com/u/1794099?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/jrieken", + "html_url": "https://github.com/jrieken", + "followers_url": "https://api.github.com/users/jrieken/followers", + "following_url": "https://api.github.com/users/jrieken/following{/other_user}", + "gists_url": "https://api.github.com/users/jrieken/gists{/gist_id}", + "starred_url": "https://api.github.com/users/jrieken/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/jrieken/subscriptions", + "organizations_url": "https://api.github.com/users/jrieken/orgs", + "repos_url": "https://api.github.com/users/jrieken/repos", + "events_url": "https://api.github.com/users/jrieken/events{/privacy}", + "received_events_url": "https://api.github.com/users/jrieken/received_events", + "type": "User", + "site_admin": false + } + ], + "milestone": { + "url": "https://api.github.com/repos/microsoft/vscode/milestones/142", + "html_url": "https://github.com/microsoft/vscode/milestone/142", + "labels_url": "https://api.github.com/repos/microsoft/vscode/milestones/142/labels", + "id": 6286096, + "node_id": "MDk6TWlsZXN0b25lNjI4NjA5Ng==", + "number": 142, + "title": "February 2021", + "description": "", + "creator": { + "login": "Tyriar", + "id": 2193314, + "node_id": "MDQ6VXNlcjIxOTMzMTQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/2193314?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/Tyriar", + "html_url": "https://github.com/Tyriar", + "followers_url": "https://api.github.com/users/Tyriar/followers", + "following_url": "https://api.github.com/users/Tyriar/following{/other_user}", + "gists_url": "https://api.github.com/users/Tyriar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/Tyriar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/Tyriar/subscriptions", + "organizations_url": "https://api.github.com/users/Tyriar/orgs", + "repos_url": "https://api.github.com/users/Tyriar/repos", + "events_url": "https://api.github.com/users/Tyriar/events{/privacy}", + "received_events_url": "https://api.github.com/users/Tyriar/received_events", + "type": "User", + "site_admin": false + }, + "open_issues": 232, + "closed_issues": 300, + "state": "open", + "created_at": "2021-01-07T18:23:10Z", + "updated_at": "2021-02-17T10:48:47Z", + "due_on": null, + "closed_at": null + }, + "comments": 15, + "created_at": "2021-01-11T06:09:50Z", + "updated_at": "2021-02-09T13:40:28Z", + "closed_at": null, + "author_association": "MEMBER", + "active_lock_reason": null, + "body": "\r\n\r\n\r\n\r\n\r\n\r\n### Problem\r\nSince the contribution point: `editor/title` is open for all the extensions, sometimes different extensions may have conflicts at this area. For example, in Java, such conflicts affect the run experience when the user installs both the Java extensions and the Code Runner extension:\r\n\r\n![image](https://user-images.githubusercontent.com/6193897/104149682-30373100-5412-11eb-84be-8f05bfa9c042.png)\r\n\r\nThis is a very open and big topic, as a author of VS Code extensions, it will be great if VS Code as a platform, can provide solutions for this issue.\r\n\r\n### Potential Solutions\r\nBelow are just rough ideas on this, it's open for discussion!\r\n\r\n#### Editor Metadata\r\nExtensions can register context value per document/editor, and register command on the editor title area according to the context value. For example. the Java Debugger can use this to mark if the current Java file is executable or not. And register the run/debug command into the editor context area if it's executable.\r\n\r\n> This can somehow achieved by using the `in` expression of the when clause, something like `resource in hasMainMethodFiles`. But we also need to [get the context value dynamically from the code](https://github.com/microsoft/vscode/issues/10471#issuecomment-718548790) to handle with the corporation between multiple extensions. \r\n\r\nMeanwhile the Java feature team can contribute changes to the Code Runner extension to align the UX (for example, hide the run button from Code Runner if the current Java file contains an executable Main class).\r\n\r\n#### Official Support for the run experience in the editor title area.\r\nThis also may have some opportunity since I believe it's somehow related with #85759, if VS Code team will consider provide official `run/debug` functionality area in the editor title.\r\n\r\n", + "performed_via_github_app": null, + "score": 1 + }, + { + "url": "https://api.github.com/repos/microsoft/vscode/issues/109277", + "repository_url": "https://api.github.com/repos/microsoft/vscode", + "labels_url": "https://api.github.com/repos/microsoft/vscode/issues/109277/labels{/name}", + "comments_url": "https://api.github.com/repos/microsoft/vscode/issues/109277/comments", + "events_url": "https://api.github.com/repos/microsoft/vscode/issues/109277/events", + "html_url": "https://github.com/microsoft/vscode/issues/109277", + "id": 728636389, + "node_id": "MDU6SXNzdWU3Mjg2MzYzODk=", + "number": 109277, + "title": "Let extensions hook into url opening", + "user": { + "login": "mjbvz", + "id": 12821956, + "node_id": "MDQ6VXNlcjEyODIxOTU2", + "avatar_url": "https://avatars.githubusercontent.com/u/12821956?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/mjbvz", + "html_url": "https://github.com/mjbvz", + "followers_url": "https://api.github.com/users/mjbvz/followers", + "following_url": "https://api.github.com/users/mjbvz/following{/other_user}", + "gists_url": "https://api.github.com/users/mjbvz/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mjbvz/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mjbvz/subscriptions", + "organizations_url": "https://api.github.com/users/mjbvz/orgs", + "repos_url": "https://api.github.com/users/mjbvz/repos", + "events_url": "https://api.github.com/users/mjbvz/events{/privacy}", + "received_events_url": "https://api.github.com/users/mjbvz/received_events", + "type": "User", + "site_admin": false + }, + "labels": [ + { + "id": 290465400, + "node_id": "MDU6TGFiZWwyOTA0NjU0MDA=", + "url": "https://api.github.com/repos/microsoft/vscode/labels/api", + "name": "api", + "color": "1d76db", + "default": false, + "description": "" + }, + { + "id": 869332220, + "node_id": "MDU6TGFiZWw4NjkzMzIyMjA=", + "url": "https://api.github.com/repos/microsoft/vscode/labels/api-proposal", + "name": "api-proposal", + "color": "c5def5", + "default": false, + "description": "" + }, + { + "id": 578047123, + "node_id": "MDU6TGFiZWw1NzgwNDcxMjM=", + "url": "https://api.github.com/repos/microsoft/vscode/labels/under-discussion", + "name": "under-discussion", + "color": "dcdcdc", + "default": false, + "description": "Issue is under discussion for relevance, priority, approach" + } + ], + "state": "open", + "locked": false, + "assignee": { + "login": "mjbvz", + "id": 12821956, + "node_id": "MDQ6VXNlcjEyODIxOTU2", + "avatar_url": "https://avatars.githubusercontent.com/u/12821956?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/mjbvz", + "html_url": "https://github.com/mjbvz", + "followers_url": "https://api.github.com/users/mjbvz/followers", + "following_url": "https://api.github.com/users/mjbvz/following{/other_user}", + "gists_url": "https://api.github.com/users/mjbvz/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mjbvz/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mjbvz/subscriptions", + "organizations_url": "https://api.github.com/users/mjbvz/orgs", + "repos_url": "https://api.github.com/users/mjbvz/repos", + "events_url": "https://api.github.com/users/mjbvz/events{/privacy}", + "received_events_url": "https://api.github.com/users/mjbvz/received_events", + "type": "User", + "site_admin": false + }, + "assignees": [ + { + "login": "mjbvz", + "id": 12821956, + "node_id": "MDQ6VXNlcjEyODIxOTU2", + "avatar_url": "https://avatars.githubusercontent.com/u/12821956?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/mjbvz", + "html_url": "https://github.com/mjbvz", + "followers_url": "https://api.github.com/users/mjbvz/followers", + "following_url": "https://api.github.com/users/mjbvz/following{/other_user}", + "gists_url": "https://api.github.com/users/mjbvz/gists{/gist_id}", + "starred_url": "https://api.github.com/users/mjbvz/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/mjbvz/subscriptions", + "organizations_url": "https://api.github.com/users/mjbvz/orgs", + "repos_url": "https://api.github.com/users/mjbvz/repos", + "events_url": "https://api.github.com/users/mjbvz/events{/privacy}", + "received_events_url": "https://api.github.com/users/mjbvz/received_events", + "type": "User", + "site_admin": false + } + ], + "milestone": { + "url": "https://api.github.com/repos/microsoft/vscode/milestones/142", + "html_url": "https://github.com/microsoft/vscode/milestone/142", + "labels_url": "https://api.github.com/repos/microsoft/vscode/milestones/142/labels", + "id": 6286096, + "node_id": "MDk6TWlsZXN0b25lNjI4NjA5Ng==", + "number": 142, + "title": "February 2021", + "description": "", + "creator": { + "login": "Tyriar", + "id": 2193314, + "node_id": "MDQ6VXNlcjIxOTMzMTQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/2193314?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/Tyriar", + "html_url": "https://github.com/Tyriar", + "followers_url": "https://api.github.com/users/Tyriar/followers", + "following_url": "https://api.github.com/users/Tyriar/following{/other_user}", + "gists_url": "https://api.github.com/users/Tyriar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/Tyriar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/Tyriar/subscriptions", + "organizations_url": "https://api.github.com/users/Tyriar/orgs", + "repos_url": "https://api.github.com/users/Tyriar/repos", + "events_url": "https://api.github.com/users/Tyriar/events{/privacy}", + "received_events_url": "https://api.github.com/users/Tyriar/received_events", + "type": "User", + "site_admin": false + }, + "open_issues": 232, + "closed_issues": 300, + "state": "open", + "created_at": "2021-01-07T18:23:10Z", + "updated_at": "2021-02-17T10:48:47Z", + "due_on": null, + "closed_at": null + }, + "comments": 10, + "created_at": "2020-10-24T02:27:26Z", + "updated_at": "2021-02-11T23:51:08Z", + "closed_at": null, + "author_association": "MEMBER", + "active_lock_reason": null, + "body": "## Overview\r\nLet extensions hook into url opening. Motivating use case: I click on a link in the integrated terminal and it opens in my [browser preview extension](https://marketplace.visualstudio.com/items?itemName=auchenberg.vscode-browser-preview)\r\n\r\nPotential places to handle links:\r\n\r\n- Links in the terminal\r\n- Links in documents\r\n- Links from the remote port forwarding views\r\n- Debugger launch?\r\n- Open external?\r\n\r\n## Additional requirements\r\n\r\n- A url opener should be able to decline opening a link\r\n\r\n Some openers may only support specific types of links, such as `localhost`\r\n\r\n- Clicking a link should activate relevant extensions\r\n\r\n We'd need a new activation event so that extensions can make sure they handle link opening\r\n\r\n- Let users fallback to VS Code's default behavior\r\n\r\n This typically is to open using the default browser\r\n\r\n- Handle multiple url openers being registered at the same time\r\n\r\n Users should be able to select which opener to use in this case. They should potentially be able to specify a default opener.\r\n", + "performed_via_github_app": null, + "score": 1 + }, + { + "url": "https://api.github.com/repos/microsoft/vscode/issues/107467", + "repository_url": "https://api.github.com/repos/microsoft/vscode", + "labels_url": "https://api.github.com/repos/microsoft/vscode/issues/107467/labels{/name}", + "comments_url": "https://api.github.com/repos/microsoft/vscode/issues/107467/comments", + "events_url": "https://api.github.com/repos/microsoft/vscode/issues/107467/events", + "html_url": "https://github.com/microsoft/vscode/issues/107467", + "id": 709128519, + "node_id": "MDU6SXNzdWU3MDkxMjg1MTk=", + "number": 107467, + "title": "Testing in VS Code", + "user": { + "login": "connor4312", + "id": 2230985, + "node_id": "MDQ6VXNlcjIyMzA5ODU=", + "avatar_url": "https://avatars.githubusercontent.com/u/2230985?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/connor4312", + "html_url": "https://github.com/connor4312", + "followers_url": "https://api.github.com/users/connor4312/followers", + "following_url": "https://api.github.com/users/connor4312/following{/other_user}", + "gists_url": "https://api.github.com/users/connor4312/gists{/gist_id}", + "starred_url": "https://api.github.com/users/connor4312/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/connor4312/subscriptions", + "organizations_url": "https://api.github.com/users/connor4312/orgs", + "repos_url": "https://api.github.com/users/connor4312/repos", + "events_url": "https://api.github.com/users/connor4312/events{/privacy}", + "received_events_url": "https://api.github.com/users/connor4312/received_events", + "type": "User", + "site_admin": false + }, + "labels": [ + { + "id": 869332220, + "node_id": "MDU6TGFiZWw4NjkzMzIyMjA=", + "url": "https://api.github.com/repos/microsoft/vscode/labels/api-proposal", + "name": "api-proposal", + "color": "c5def5", + "default": false, + "description": "" + }, + { + "id": 293426086, + "node_id": "MDU6TGFiZWwyOTM0MjYwODY=", + "url": "https://api.github.com/repos/microsoft/vscode/labels/plan-item", + "name": "plan-item", + "color": "dcdcdc", + "default": false, + "description": "VS Code - planned item for upcoming" + }, + { + "id": 578047123, + "node_id": "MDU6TGFiZWw1NzgwNDcxMjM=", + "url": "https://api.github.com/repos/microsoft/vscode/labels/under-discussion", + "name": "under-discussion", + "color": "dcdcdc", + "default": false, + "description": "Issue is under discussion for relevance, priority, approach" + } + ], + "state": "open", + "locked": false, + "assignee": { + "login": "connor4312", + "id": 2230985, + "node_id": "MDQ6VXNlcjIyMzA5ODU=", + "avatar_url": "https://avatars.githubusercontent.com/u/2230985?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/connor4312", + "html_url": "https://github.com/connor4312", + "followers_url": "https://api.github.com/users/connor4312/followers", + "following_url": "https://api.github.com/users/connor4312/following{/other_user}", + "gists_url": "https://api.github.com/users/connor4312/gists{/gist_id}", + "starred_url": "https://api.github.com/users/connor4312/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/connor4312/subscriptions", + "organizations_url": "https://api.github.com/users/connor4312/orgs", + "repos_url": "https://api.github.com/users/connor4312/repos", + "events_url": "https://api.github.com/users/connor4312/events{/privacy}", + "received_events_url": "https://api.github.com/users/connor4312/received_events", + "type": "User", + "site_admin": false + }, + "assignees": [ + { + "login": "connor4312", + "id": 2230985, + "node_id": "MDQ6VXNlcjIyMzA5ODU=", + "avatar_url": "https://avatars.githubusercontent.com/u/2230985?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/connor4312", + "html_url": "https://github.com/connor4312", + "followers_url": "https://api.github.com/users/connor4312/followers", + "following_url": "https://api.github.com/users/connor4312/following{/other_user}", + "gists_url": "https://api.github.com/users/connor4312/gists{/gist_id}", + "starred_url": "https://api.github.com/users/connor4312/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/connor4312/subscriptions", + "organizations_url": "https://api.github.com/users/connor4312/orgs", + "repos_url": "https://api.github.com/users/connor4312/repos", + "events_url": "https://api.github.com/users/connor4312/events{/privacy}", + "received_events_url": "https://api.github.com/users/connor4312/received_events", + "type": "User", + "site_admin": false + }, + { + "login": "sandy081", + "id": 10746682, + "node_id": "MDQ6VXNlcjEwNzQ2Njgy", + "avatar_url": "https://avatars.githubusercontent.com/u/10746682?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/sandy081", + "html_url": "https://github.com/sandy081", + "followers_url": "https://api.github.com/users/sandy081/followers", + "following_url": "https://api.github.com/users/sandy081/following{/other_user}", + "gists_url": "https://api.github.com/users/sandy081/gists{/gist_id}", + "starred_url": "https://api.github.com/users/sandy081/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/sandy081/subscriptions", + "organizations_url": "https://api.github.com/users/sandy081/orgs", + "repos_url": "https://api.github.com/users/sandy081/repos", + "events_url": "https://api.github.com/users/sandy081/events{/privacy}", + "received_events_url": "https://api.github.com/users/sandy081/received_events", + "type": "User", + "site_admin": false + } + ], + "milestone": { + "url": "https://api.github.com/repos/microsoft/vscode/milestones/142", + "html_url": "https://github.com/microsoft/vscode/milestone/142", + "labels_url": "https://api.github.com/repos/microsoft/vscode/milestones/142/labels", + "id": 6286096, + "node_id": "MDk6TWlsZXN0b25lNjI4NjA5Ng==", + "number": 142, + "title": "February 2021", + "description": "", + "creator": { + "login": "Tyriar", + "id": 2193314, + "node_id": "MDQ6VXNlcjIxOTMzMTQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/2193314?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/Tyriar", + "html_url": "https://github.com/Tyriar", + "followers_url": "https://api.github.com/users/Tyriar/followers", + "following_url": "https://api.github.com/users/Tyriar/following{/other_user}", + "gists_url": "https://api.github.com/users/Tyriar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/Tyriar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/Tyriar/subscriptions", + "organizations_url": "https://api.github.com/users/Tyriar/orgs", + "repos_url": "https://api.github.com/users/Tyriar/repos", + "events_url": "https://api.github.com/users/Tyriar/events{/privacy}", + "received_events_url": "https://api.github.com/users/Tyriar/received_events", + "type": "User", + "site_admin": false + }, + "open_issues": 232, + "closed_issues": 300, + "state": "open", + "created_at": "2021-01-07T18:23:10Z", + "updated_at": "2021-02-17T10:48:47Z", + "due_on": null, + "closed_at": null + }, + "comments": 53, + "created_at": "2020-09-25T17:19:53Z", + "updated_at": "2021-02-16T21:11:36Z", + "closed_at": null, + "author_association": "MEMBER", + "active_lock_reason": null, + "body": "## State of the World\r\n\r\nTesting support in VS Code has been a feature request for [a long time](https://github.com/microsoft/vscode/issues/9505). The VS Code community has build excellent extensions around testing, for example:\r\n\r\n- The [Test Explorer UI](https://marketplace.visualstudio.com/items?itemName=hbenl.vscode-test-explorer) from @hbenl\r\n- [Wallaby.js](https://wallabyjs.com/) from the Wallaby team\r\n- [Jest](https://marketplace.visualstudio.com/items?itemName=Orta.vscode-jest) from @orta\r\n- ...and many more\r\n\r\nEach implementation of testing presents a different set of features, UI, and idiomaticity. Because there is no sanctioned approach to tests in VS Code, extension developers tend to make bespoke implementations, as we've seen in the Python and Java language extensions. Ideally, like in debugging, a VS Code user would have just about the same experience as they work between projects and languages.\r\n\r\n## VS Code's Approach\r\n\r\n> Investigate how VS Code can improve the testing support. Several extensions are already providing testing support, explore what APIs/UIs could be added to improve these testing extensions and the test running experience. -- [2020 Roadmap](https://github.com/microsoft/vscode/wiki/Roadmap#testing)\r\n\r\nThe Test Explorer UI presents the best point of inspiration for us, as there are many existing extensions built on its API: it's capable and proven. Regardless of the direction we take in VS Code, we should have a way for its Test Adapters to be upgraded to the new world.\r\n\r\nWallaby is an excellent extension, but it's tailored and purpose-built to JavaScript, and includes functionality which is not readily portable to other languages. While it is a good source for inspiration, we're not aiming to encompass Wallaby's feature set in the extension points we provide, at least not yet.\r\n\r\nWe're prototyping an API in the extension host, but there are a number of approaches we can take:\r\n\r\n\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n
Extension Host ('traditional' VS Code API)'Test Protocol' (like DAP/LSP)Extension (like existing test explorer)
\r\n\t\t\t+ Simple to adopt for extension authors
\r\n\t\t\t+ Easier to manage state
\r\n\t\t\t+ Clear way to build 'official' test extensions
\r\n\t\t
\r\n\t\t\t+ Encourages keeping expensive work in child processes
\r\n\t\t\t+ Could be theoretically shared with VS and other editors
\r\n\t\t
\r\n\t\t\t+ Keep VS Code core slim
\r\n\t\t\t+ Unclear whether there's significant functionality we'd want that's not already possible in exthost api
\r\n\t\t
\r\n\t\t\t- The 'obvious path' is doing heavy lifting in the extension host process, which is undesirable
\r\n\t\t
\r\n\t\t\t- Additional implementation and maintainence complexity for VS Code
\r\n\t\t\t- Less friendly, additional complexity than TS APIs for extension authors
\r\n\t\t
\r\n\t\t\t- Additional extension and set of libraries to maintain+version for types and implementation
\r\n\t\t\t- Less clear there's an official pathway for test extensions
\r\n\t\t
\r\n\r\n## API Design\r\n\r\nThe following is a working draft of an API design. It should not be considered final, or anything close to final. This post will be edited as it evolves.\r\n\r\n#### Changes versus the [Test Adapter API](https://github.com/hbenl/vscode-test-adapter-api)\r\n\r\nAs mentioned, the test adapter API and this one provide a similar end user experience. Here are the notable changes we made:\r\n\r\n- The test adapter API does not distinguish between watching a workspace and watching a file. In some cases, there is an existing process that reads workspace tests (such as a language server in Java) or it's not much more expensive to get workspace tests than file tests (such as mocha, perhaps). However, some cases, like Go, providing tests for a single file can be done very cheaply and efficiently without needing to involve the workspace.\r\n\r\n\tIn this API we expect the `TestProvider` to, after activation, always provide tests for the visible text editors, and we only request tests for the entire workspace when required (i.e. when the UI needs to enumerate them).\r\n\r\n- We have modeled the test state more closely after the existing `DiagnosticCollection`, where the Test Adapter API uses only events to enumerate tests and does not have a central collection.\r\n\r\n- The Test Adapter API makes the distinction between suites and tests, we do not. They have almost identical capabilities, and in [at least one scenario](https://blog.golang.org/subtests) the 'suites' are more like tests and the leaf 'tests' cannot be run individually.\r\n\r\n- We use object identity rather than ID for referencing tests. This is in line with other items in the VS Code API, including Diagnostics.\r\n\r\n#### Ideas and Open Questions\r\n\r\n- We do not (yet) have a concept of test invalidation and auto-run, which in the test adapter API via the \"retire\" event. We are still looking into how this can best be implemented.\r\n\t\r\n\tIn a golden scenario, invalidation of tests would be done by a language server which can intelligently determine specific tests that should be invalidated when a file or a file dependency changes. Maybe this is still handled by an event on the TestProvider, but if we take a \"Test Protocol\" approach then coordination will be harder.\r\n- As marked in the `todo`, we will expose APIs for other extensions to read test state and build UI, but this is not yet included in the API design.\r\n- How should errors loading tests be handled? Emit diagnostics or have some test-specific code?\r\n\r\n- We would like to support code coverage in testing as well, but that is further down the line.\r\n\r\n- How can we let users learn about/onboard to testing from within VS Code?\r\n\r\n### API\r\n\r\nSee the current working proposal in https://github.com/microsoft/vscode/blob/master/src/vs/vscode.proposed.d.ts (ctrl+f for 107467)", + "performed_via_github_app": null, + "score": 1 + }, + { + "url": "https://api.github.com/repos/microsoft/vscode/issues/105690", + "repository_url": "https://api.github.com/repos/microsoft/vscode", + "labels_url": "https://api.github.com/repos/microsoft/vscode/issues/105690/labels{/name}", + "comments_url": "https://api.github.com/repos/microsoft/vscode/issues/105690/comments", + "events_url": "https://api.github.com/repos/microsoft/vscode/issues/105690/events", + "html_url": "https://github.com/microsoft/vscode/issues/105690", + "id": 688793797, + "node_id": "MDU6SXNzdWU2ODg3OTM3OTc=", + "number": 105690, + "title": "Extension API for Inline Values", + "user": { + "login": "weinand", + "id": 1898161, + "node_id": "MDQ6VXNlcjE4OTgxNjE=", + "avatar_url": "https://avatars.githubusercontent.com/u/1898161?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/weinand", + "html_url": "https://github.com/weinand", + "followers_url": "https://api.github.com/users/weinand/followers", + "following_url": "https://api.github.com/users/weinand/following{/other_user}", + "gists_url": "https://api.github.com/users/weinand/gists{/gist_id}", + "starred_url": "https://api.github.com/users/weinand/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/weinand/subscriptions", + "organizations_url": "https://api.github.com/users/weinand/orgs", + "repos_url": "https://api.github.com/users/weinand/repos", + "events_url": "https://api.github.com/users/weinand/events{/privacy}", + "received_events_url": "https://api.github.com/users/weinand/received_events", + "type": "User", + "site_admin": false + }, + "labels": [ + { + "id": 290465400, + "node_id": "MDU6TGFiZWwyOTA0NjU0MDA=", + "url": "https://api.github.com/repos/microsoft/vscode/labels/api", + "name": "api", + "color": "1d76db", + "default": false, + "description": "" + }, + { + "id": 869332220, + "node_id": "MDU6TGFiZWw4NjkzMzIyMjA=", + "url": "https://api.github.com/repos/microsoft/vscode/labels/api-proposal", + "name": "api-proposal", + "color": "c5def5", + "default": false, + "description": "" + }, + { + "id": 291054922, + "node_id": "MDU6TGFiZWwyOTEwNTQ5MjI=", + "url": "https://api.github.com/repos/microsoft/vscode/labels/debug", + "name": "debug", + "color": "1d76db", + "default": false, + "description": "Debug viewlet, configurations, breakpoints, adapter issues" + }, + { + "id": 272689392, + "node_id": "MDU6TGFiZWwyNzI2ODkzOTI=", + "url": "https://api.github.com/repos/microsoft/vscode/labels/feature-request", + "name": "feature-request", + "color": "dcdcdc", + "default": false, + "description": "Request for new features or functionality" + } + ], + "state": "open", + "locked": false, + "assignee": { + "login": "weinand", + "id": 1898161, + "node_id": "MDQ6VXNlcjE4OTgxNjE=", + "avatar_url": "https://avatars.githubusercontent.com/u/1898161?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/weinand", + "html_url": "https://github.com/weinand", + "followers_url": "https://api.github.com/users/weinand/followers", + "following_url": "https://api.github.com/users/weinand/following{/other_user}", + "gists_url": "https://api.github.com/users/weinand/gists{/gist_id}", + "starred_url": "https://api.github.com/users/weinand/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/weinand/subscriptions", + "organizations_url": "https://api.github.com/users/weinand/orgs", + "repos_url": "https://api.github.com/users/weinand/repos", + "events_url": "https://api.github.com/users/weinand/events{/privacy}", + "received_events_url": "https://api.github.com/users/weinand/received_events", + "type": "User", + "site_admin": false + }, + "assignees": [ + { + "login": "weinand", + "id": 1898161, + "node_id": "MDQ6VXNlcjE4OTgxNjE=", + "avatar_url": "https://avatars.githubusercontent.com/u/1898161?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/weinand", + "html_url": "https://github.com/weinand", + "followers_url": "https://api.github.com/users/weinand/followers", + "following_url": "https://api.github.com/users/weinand/following{/other_user}", + "gists_url": "https://api.github.com/users/weinand/gists{/gist_id}", + "starred_url": "https://api.github.com/users/weinand/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/weinand/subscriptions", + "organizations_url": "https://api.github.com/users/weinand/orgs", + "repos_url": "https://api.github.com/users/weinand/repos", + "events_url": "https://api.github.com/users/weinand/events{/privacy}", + "received_events_url": "https://api.github.com/users/weinand/received_events", + "type": "User", + "site_admin": false + } + ], + "milestone": { + "url": "https://api.github.com/repos/microsoft/vscode/milestones/142", + "html_url": "https://github.com/microsoft/vscode/milestone/142", + "labels_url": "https://api.github.com/repos/microsoft/vscode/milestones/142/labels", + "id": 6286096, + "node_id": "MDk6TWlsZXN0b25lNjI4NjA5Ng==", + "number": 142, + "title": "February 2021", + "description": "", + "creator": { + "login": "Tyriar", + "id": 2193314, + "node_id": "MDQ6VXNlcjIxOTMzMTQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/2193314?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/Tyriar", + "html_url": "https://github.com/Tyriar", + "followers_url": "https://api.github.com/users/Tyriar/followers", + "following_url": "https://api.github.com/users/Tyriar/following{/other_user}", + "gists_url": "https://api.github.com/users/Tyriar/gists{/gist_id}", + "starred_url": "https://api.github.com/users/Tyriar/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/Tyriar/subscriptions", + "organizations_url": "https://api.github.com/users/Tyriar/orgs", + "repos_url": "https://api.github.com/users/Tyriar/repos", + "events_url": "https://api.github.com/users/Tyriar/events{/privacy}", + "received_events_url": "https://api.github.com/users/Tyriar/received_events", + "type": "User", + "site_admin": false + }, + "open_issues": 232, + "closed_issues": 300, + "state": "open", + "created_at": "2021-01-07T18:23:10Z", + "updated_at": "2021-02-17T10:48:47Z", + "due_on": null, + "closed_at": null + }, + "comments": 7, + "created_at": "2020-08-30T21:21:23Z", + "updated_at": "2021-02-08T05:21:59Z", + "closed_at": null, + "author_association": "MEMBER", + "active_lock_reason": null, + "body": "Today the \"Show Inline Values\" feature of VS Code's debugger is based on a generic implementation in the VS Code core and provides neither customisability through settings, nor extensibility via extensions.\r\n\r\nAs a consequence, it is not a perfect fit for all languages (e.g. #101797) and sometimes even shows incorrect values because it doesn't understand the scope regions of the underlying language. \r\n\r\nThis features asks for an extension API that either replaces the built-in implementation completely or allows to replace parts of the implementation with custom code.\r\n", + "performed_via_github_app": null, + "score": 1 + } + ] + } + ] } ] \ No newline at end of file From c1230f88475b7b73075d81df5806141ae30e6e33 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 17 Feb 2021 14:07:29 +0100 Subject: [PATCH 249/325] shared process - log errors/crashes also to active window --- .../sharedProcess/electron-main/sharedProcess.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts b/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts index 966a8830bf6..889a2c3b85f 100644 --- a/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts +++ b/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts @@ -15,6 +15,7 @@ import { ISharedProcess, ISharedProcessConfiguration } from 'vs/platform/sharedP import { Disposable } from 'vs/base/common/lifecycle'; import { connect as connectMessagePort } from 'vs/base/parts/ipc/electron-main/ipc.mp'; import { assertIsDefined } from 'vs/base/common/types'; +import { onUnexpectedError } from 'vs/base/common/errors'; export class SharedProcess extends Disposable implements ISharedProcess { @@ -201,9 +202,11 @@ export class SharedProcess extends Disposable implements ISharedProcess { this.window.on('close', this.windowCloseListener); // Crashes & Unrsponsive & Failed to load - this.window.webContents.on('render-process-gone', (event, details) => this.logService.error(`SharedProcess: crashed (detail: ${details?.reason})`)); - this.window.on('unresponsive', () => this.logService.error('SharedProcess: detected unresponsive window')); - this.window.webContents.on('did-fail-load', (event, errorCode, errorDescription) => this.logService.warn('SharedProcess: failed to load window, ', errorDescription)); + // We use `onUnexpectedError` explicitly because the error handler + // will send the error to the active window to log in devtools too + this.window.webContents.on('render-process-gone', (event, details) => onUnexpectedError(new Error(`SharedProcess: crashed (detail: ${details?.reason})`))); + this.window.on('unresponsive', () => onUnexpectedError(new Error('SharedProcess: detected unresponsive window'))); + this.window.webContents.on('did-fail-load', (event, errorCode, errorDescription) => onUnexpectedError(new Error(`SharedProcess: failed to load window: ${errorDescription}`))); } spawn(userEnv: NodeJS.ProcessEnv): void { From f2a1ecc9a7eff37f039855a8bf3abab0aa2c422b Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru Date: Wed, 17 Feb 2021 13:37:48 +0100 Subject: [PATCH 250/325] Add workspace trust banner + UI polish --- .../browser/workspaceTrustEditor.css | 32 +++++++++++-------- .../workspace/browser/workspaceTrustEditor.ts | 12 +++++++ 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css index 371217bd035..fb9e3efbd95 100644 --- a/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css +++ b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css @@ -17,7 +17,8 @@ } .workspace-trust-editor.settings-editor > .workspace-trust-header { - border-bottom: solid 1px; + padding: 14px; + border: solid 1px; } .workspace-trust-editor.settings-editor .workspace-trust-header .workspace-trust-title { @@ -27,27 +28,22 @@ } /** Buttons Container */ -.workspace-trust-editor.settings-editor .workspace-trust-header .workspace-trust-buttons-row { +.workspace-trust-editor.settings-editor .workspace-trust-header .workspace-trust-buttons-row { display: flex; align-items: center; justify-content: flex-end; - padding-right: 1px; + padding: 20px 0 10px 0; overflow: hidden; /* buttons row should never overflow */ -} - -.workspace-trust-editor.settings-editor .workspace-trust-header .workspace-trust-buttons-row { - display: flex; white-space: nowrap; - padding: 20px 10px 10px; } /** Buttons */ -.workspace-trust-editor.settings-editor .workspace-trust-header .workspace-trust-buttons-row .workspace-trust-buttons { +.workspace-trust-editor.settings-editor .workspace-trust-header .workspace-trust-buttons-row .workspace-trust-buttons { display: flex; overflow: hidden; } -.workspace-trust-editor.settings-editor .workspace-trust-header .workspace-trust-buttons-row .workspace-trust-buttons .monaco-button { +.workspace-trust-editor.settings-editor .workspace-trust-header .workspace-trust-buttons-row .workspace-trust-buttons .monaco-button { width: fit-content; width: -moz-fit-content; padding: 5px 10px; @@ -57,17 +53,27 @@ outline-offset: 2px !important; } -.monaco-workbench.vs .workspace-trust-editor.settings-editor > .workspace-trust-header { +.monaco-workbench.vs .workspace-trust-editor.settings-editor > .workspace-trust-header.workspace-trust-unknown { border-color: #cccccc; } -.monaco-workbench.vs-dark .workspace-trust-editor.settings-editor > .workspace-trust-header{ +.monaco-workbench.vs-dark .workspace-trust-editor.settings-editor > .workspace-trust-header.workspace-trust-unknown { border-color: #3c3c3c; } +.monaco-workbench.vs .workspace-trust-editor.settings-editor > .workspace-trust-header.workspace-trust-untrusted, +.monaco-workbench.vs-dark .workspace-trust-editor.settings-editor > .workspace-trust-header.workspace-trust-untrusted { + border-color: #FF0000; +} + +.monaco-workbench.vs .workspace-trust-editor.settings-editor > .workspace-trust-header.workspace-trust-trusted, +.monaco-workbench.vs-dark .workspace-trust-editor.settings-editor > .workspace-trust-header.workspace-trust-trusted { + border-color: #327E36; +} /** Settings */ .workspace-trust-editor.settings-editor > .settings-body .settings-tree-container .monaco-list-row .monaco-tl-contents { - padding-left: 0px; + padding-left: 0; + padding-right: 0; } diff --git a/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts index 33bc5e1d73a..47e60a806c1 100644 --- a/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts +++ b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts @@ -68,6 +68,17 @@ export class WorkspaceTrustEditor extends EditorPane { this.workspaceTrustEditorModel = model; } + private getHeaderContainerClass(trustState: WorkspaceTrustState): string { + switch (trustState) { + case WorkspaceTrustState.Trusted: + return 'workspace-trust-header workspace-trust-trusted'; + case WorkspaceTrustState.Untrusted: + return 'workspace-trust-header workspace-trust-untrusted'; + case WorkspaceTrustState.Unknown: + return 'workspace-trust-header workspace-trust-unknown'; + } + } + private getHeaderTitleText(trustState: WorkspaceTrustState): string { switch (trustState) { case WorkspaceTrustState.Trusted: @@ -93,6 +104,7 @@ export class WorkspaceTrustEditor extends EditorPane { private render(model: WorkspaceTrustEditorModel): void { this.headerTitle.innerText = this.getHeaderTitleText(model.currentWorkspaceTrustState); this.headerDescription.innerText = this.getHeaderDescriptionText(model.currentWorkspaceTrustState); + this.headerContainer.className = this.getHeaderContainerClass(model.currentWorkspaceTrustState); clearNode(this.headerButtons); const buttonBar = this._register(new ButtonBar(this.headerButtons)); From 8615af08b3dbc7f92f503906d4b1e8e5fb333f48 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru Date: Wed, 17 Feb 2021 14:11:24 +0100 Subject: [PATCH 251/325] Tweak input field width --- .../contrib/workspace/browser/workspaceTrustEditor.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css index fb9e3efbd95..03bfb124126 100644 --- a/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css +++ b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css @@ -77,3 +77,7 @@ padding-right: 0; } +.workspace-trust-editor.settings-editor > .settings-body .settings-tree-container .monaco-list-row .monaco-tl-contents .setting-list-edit-row > .setting-list-valueInput { + width: 100%; + max-width: 100%; +} From 5870204e95c504eb3c15f39295537c496bbb8765 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 17 Feb 2021 14:19:40 +0100 Subject: [PATCH 252/325] make notebook and cell metadata classes, https://github.com/microsoft/vscode/issues/116333 --- .../notebook.document.test.ts | 4 +- .../src/singlefolder-tests/notebook.test.ts | 32 ++-- .../vscode-notebook-tests/src/extension.ts | 10 +- src/vs/vscode.proposed.d.ts | 144 ++++++------------ .../workbench/api/common/extHost.api.impl.ts | 6 + .../workbench/api/common/extHostNotebook.ts | 40 +++-- .../api/common/extHostTypeConverters.ts | 4 +- 7 files changed, 97 insertions(+), 143 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts index 34a8218e3a1..0d5ecc671fa 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts @@ -12,8 +12,8 @@ suite('Notebook Document', function () { const contentProvider = new class implements vscode.NotebookContentProvider { async openNotebook(uri: vscode.Uri, _openContext: vscode.NotebookDocumentOpenContext): Promise { return { - cells: [{ cellKind: vscode.NotebookCellKind.Code, source: uri.toString(), language: 'javascript', metadata: {}, outputs: [] }], - metadata: {} + cells: [{ cellKind: vscode.NotebookCellKind.Code, source: uri.toString(), language: 'javascript', metadata: new vscode.NotebookCellMetadata(), outputs: [] }], + metadata: new vscode.NotebookDocumentMetadata() }; } async resolveNotebook(_document: vscode.NotebookDocument, _webview: vscode.NotebookCommunication) { diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts index 81a03ed3250..c21be1935ab 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts @@ -90,24 +90,20 @@ suite('Notebook API tests', function () { openNotebook: async (_resource: vscode.Uri): Promise => { if (/.*empty\-.*\.vsctestnb$/.test(_resource.path)) { return { - metadata: {}, + metadata: new vscode.NotebookDocumentMetadata(), cells: [] }; } const dto: vscode.NotebookData = { - metadata: { - custom: { testMetadata: false } - }, + metadata: new vscode.NotebookDocumentMetadata().with({ custom: { testMetadata: false } }), cells: [ { source: 'test', language: 'typescript', cellKind: vscode.NotebookCellKind.Code, outputs: [], - metadata: { - custom: { testCellMetadata: 123 } - } + metadata: new vscode.NotebookCellMetadata().with({ custom: { testCellMetadata: 123 } }) } ] }; @@ -599,7 +595,7 @@ suite('Notebook API tests', function () { await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); await vscode.window.activeNotebookEditor!.edit(editBuilder => { - editBuilder.replaceCellMetadata(0, { inputCollapsed: true, executionOrder: 17 }); + editBuilder.replaceCellMetadata(0, new vscode.NotebookCellMetadata().with({ inputCollapsed: true, executionOrder: 17 })); }); const document = vscode.window.activeNotebookEditor?.document!; @@ -620,7 +616,7 @@ suite('Notebook API tests', function () { const event = asPromise(vscode.notebook.onDidChangeCellMetadata); await vscode.window.activeNotebookEditor!.edit(editBuilder => { - editBuilder.replaceCellMetadata(0, { inputCollapsed: true, executionOrder: 17 }); + editBuilder.replaceCellMetadata(0, new vscode.NotebookCellMetadata().with({ inputCollapsed: true, executionOrder: 17 })); }); const data = await event; @@ -642,7 +638,7 @@ suite('Notebook API tests', function () { const version = vscode.window.activeNotebookEditor!.document.version; await vscode.window.activeNotebookEditor!.edit(editBuilder => { editBuilder.replaceCells(1, 0, [{ cellKind: vscode.NotebookCellKind.Code, language: 'javascript', source: 'test 2', outputs: [], metadata: undefined }]); - editBuilder.replaceCellMetadata(0, { runnable: false }); + editBuilder.replaceCellMetadata(0, new vscode.NotebookCellMetadata().with({ runnable: false })); }); await cellsChangeEvent; @@ -661,7 +657,7 @@ suite('Notebook API tests', function () { const version = vscode.window.activeNotebookEditor!.document.version; await vscode.window.activeNotebookEditor!.edit(editBuilder => { editBuilder.replaceCells(1, 0, [{ cellKind: vscode.NotebookCellKind.Code, language: 'javascript', source: 'test 2', outputs: [], metadata: undefined }]); - editBuilder.replaceCellMetadata(0, { runnable: false }); + editBuilder.replaceCellMetadata(0, new vscode.NotebookCellMetadata().with({ runnable: false })); }); await cellsChangeEvent; @@ -876,14 +872,14 @@ suite('Notebook API tests', function () { assert.strictEqual(cell.outputs.length, 0); let metadataChangeEvent = asPromise(vscode.notebook.onDidChangeCellMetadata); - await updateCellMetadata(resource, cell, { ...cell.metadata, runnable: false }); + await updateCellMetadata(resource, cell, cell.metadata.with({ runnable: false })); await metadataChangeEvent; await vscode.commands.executeCommand('notebook.cell.execute'); assert.strictEqual(cell.outputs.length, 0, 'should not execute'); // not runnable, didn't work metadataChangeEvent = asPromise(vscode.notebook.onDidChangeCellMetadata); - await updateCellMetadata(resource, cell, { ...cell.metadata, runnable: true }); + await updateCellMetadata(resource, cell, cell.metadata.with({ runnable: true })); await metadataChangeEvent; await vscode.commands.executeCommand('notebook.cell.execute'); @@ -904,7 +900,7 @@ suite('Notebook API tests', function () { assert.strictEqual(cell.outputs.length, 0); await withEvent(vscode.notebook.onDidChangeNotebookDocumentMetadata, async event => { - updateNotebookMetadata(editor.document.uri, { ...editor.document.metadata, runnable: false }); + updateNotebookMetadata(editor.document.uri, editor.document.metadata.with({ runnable: false })); await event; }); @@ -912,7 +908,7 @@ suite('Notebook API tests', function () { assert.strictEqual(cell.outputs.length, 0, 'should not execute'); // not runnable, didn't work await withEvent(vscode.notebook.onDidChangeNotebookDocumentMetadata, async event => { - updateNotebookMetadata(editor.document.uri, { ...editor.document.metadata, runnable: true }); + updateNotebookMetadata(editor.document.uri, editor.document.metadata.with({ runnable: true })); await event; }); @@ -952,7 +948,7 @@ suite('Notebook API tests', function () { const cell = editor.document.cells[0]; await withEvent(vscode.notebook.onDidChangeNotebookDocumentMetadata, async event => { - updateNotebookMetadata(editor.document.uri, { ...editor.document.metadata, runnable: true }); + updateNotebookMetadata(editor.document.uri, editor.document.metadata.with({ runnable: true })); await event; }); @@ -993,7 +989,7 @@ suite('Notebook API tests', function () { const cell = editor.document.cells[0]; const metadataChangeEvent = asPromise(vscode.notebook.onDidChangeNotebookDocumentMetadata); - updateNotebookMetadata(editor.document.uri, { ...editor.document.metadata, runnable: true }); + updateNotebookMetadata(editor.document.uri, editor.document.metadata.with({ runnable: true })); await metadataChangeEvent; assert.strictEqual(editor.document.metadata.runnable, true); @@ -1033,7 +1029,7 @@ suite('Notebook API tests', function () { const cell = editor.document.cells[0]; const metadataChangeEvent = asPromise(vscode.notebook.onDidChangeNotebookDocumentMetadata); - updateNotebookMetadata(editor.document.uri, { ...editor.document.metadata, runnable: true }); + updateNotebookMetadata(editor.document.uri, editor.document.metadata.with({ runnable: true })); await metadataChangeEvent; await vscode.commands.executeCommand('notebook.cell.execute'); diff --git a/extensions/vscode-notebook-tests/src/extension.ts b/extensions/vscode-notebook-tests/src/extension.ts index bf66b529bc2..55231411594 100644 --- a/extensions/vscode-notebook-tests/src/extension.ts +++ b/extensions/vscode-notebook-tests/src/extension.ts @@ -23,25 +23,21 @@ export function activate(context: vscode.ExtensionContext): any { context.subscriptions.push(vscode.notebook.registerNotebookContentProvider('notebookSmokeTest', { openNotebook: async (_resource: vscode.Uri) => { const dto: vscode.NotebookData = { - metadata: {}, + metadata: new vscode.NotebookDocumentMetadata(), cells: [ { source: 'code()', language: 'typescript', cellKind: vscode.NotebookCellKind.Code, outputs: [], - metadata: { - custom: { testCellMetadata: 123 } - } + metadata: new vscode.NotebookCellMetadata().with({ custom: { testCellMetadata: 123 } }) }, { source: 'Markdown Cell', language: 'markdown', cellKind: vscode.NotebookCellKind.Markdown, outputs: [], - metadata: { - custom: { testCellMetadata: 123 } - } + metadata: new vscode.NotebookCellMetadata().with({ custom: { testCellMetadata: 123 } }) } ] }; diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index a06d8165fab..ce9a5668450 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1162,34 +1162,44 @@ declare module 'vscode' { Idle = 2 } - // TODO@API - // make this a class, allow modified using with-pattern - export interface NotebookCellMetadata { + export class NotebookCellMetadata { /** * Controls whether a cell's editor is editable/readonly. */ - editable?: boolean; - + readonly editable?: boolean; /** * Controls if the cell has a margin to support the breakpoint UI. * This metadata is ignored for markdown cell. */ - breakpointMargin?: boolean; - + readonly breakpointMargin?: boolean; /** * Whether a code cell's editor is collapsed */ - inputCollapsed?: boolean; - + readonly outputCollapsed?: boolean; /** * Whether a code cell's outputs are collapsed */ - outputCollapsed?: boolean; - + readonly inputCollapsed?: boolean; /** * Additional attributes of a cell metadata. */ - custom?: { [key: string]: any; }; + readonly custom?: Record; + + // todo@API duplicates status bar API + readonly statusMessage?: string; + + // run related API, will be removed + readonly runnable?: boolean; + readonly hasExecutionOrder?: boolean; + readonly executionOrder?: number; + readonly runState?: NotebookCellRunState; + readonly runStartTime?: number; + readonly lastRunDuration?: number; + + constructor(editable?: boolean, breakpointMargin?: boolean, runnable?: boolean, hasExecutionOrder?: boolean, executionOrder?: number, runState?: NotebookCellRunState, runStartTime?: number, statusMessage?: string, lastRunDuration?: number, inputCollapsed?: boolean, outputCollapsed?: boolean, custom?: Record) + + // todo@API write a proper signature + with(change: Partial>): NotebookCellMetadata; } // todo@API support ids https://github.com/jupyter/enhancement-proposals/blob/master/62-cell-id/cell-id.md @@ -1201,39 +1211,48 @@ declare module 'vscode' { readonly document: TextDocument; readonly language: string; readonly outputs: readonly NotebookCellOutput[]; - readonly metadata: NotebookCellMetadata; - /** @deprecated use WorkspaceEdit.replaceCellOutput */ - // outputs: CellOutput[]; - // readonly outputs2: NotebookCellOutput[]; - /** @deprecated use WorkspaceEdit.replaceCellMetadata */ - // metadata: NotebookCellMetadata; + readonly metadata: NotebookCellMetadata } + export class NotebookDocumentMetadata { - export interface NotebookDocumentMetadata { /** * Controls if users can add or delete cells * Defaults to true */ - editable?: boolean; - + readonly editable: boolean; /** * Default value for [cell editable metadata](#NotebookCellMetadata.editable). * Defaults to true. */ - cellEditable?: boolean; - displayOrder?: GlobPattern[]; - + readonly cellEditable: boolean; /** * Additional attributes of the document metadata. */ - custom?: { [key: string]: any; }; - + readonly custom: { [key: string]: any; }; /** * Whether the document is trusted, default to true * When false, insecure outputs like HTML, JavaScript, SVG will not be rendered. */ - trusted?: boolean; + readonly trusted: boolean; + + // todo@API how does glob apply to mime times? + readonly displayOrder: GlobPattern[]; + + // todo@API is this a kernel property? + readonly cellHasExecutionOrder: boolean; + + // run related, remove infer from kernel, exec + // todo@API infer from kernel + // todo@API remove + readonly runnable: boolean; + readonly cellRunnable: boolean; + readonly runState: NotebookRunState; + + constructor(editable?: boolean, runnable?: boolean, cellEditable?: boolean, cellRunnable?: boolean, cellHasExecutionOrder?: boolean, displayOrder?: GlobPattern[], custom?: { [key: string]: any; }, runState?: NotebookRunState, trusted?: boolean); + + // TODO@API make this a proper signature + with(change: Partial>): NotebookDocumentMetadata; } export interface NotebookDocumentContentOptions { @@ -1640,34 +1659,6 @@ declare module 'vscode' { //#region https://github.com/microsoft/vscode/issues/106744, NotebookKernel - export interface NotebookDocumentMetadata { - - /** - * Controls whether the full notebook can be run at once. - * Defaults to true - */ - // todo@API infer from kernel - // todo@API remove - runnable?: boolean; - - /** - * Default value for [cell runnable metadata](#NotebookCellMetadata.runnable). - * Defaults to true. - */ - cellRunnable?: boolean; - - /** - * Default value for [cell hasExecutionOrder metadata](#NotebookCellMetadata.hasExecutionOrder). - * Defaults to true. - */ - cellHasExecutionOrder?: boolean; - - /** - * The document's current run state - */ - runState?: NotebookRunState; - } - // todo@API use the NotebookCellExecution-object as a container to model and enforce // the flow of a cell execution @@ -1689,49 +1680,6 @@ declare module 'vscode' { // export const onDidStartNotebookCellExecution: Event; // export const onDidStopNotebookCellExecution: Event; - export interface NotebookCellMetadata { - - /** - * Controls if the cell is executable. - * This metadata is ignored for markdown cell. - */ - // todo@API infer from kernel - runnable?: boolean; - - /** - * Whether the [execution order](#NotebookCellMetadata.executionOrder) indicator will be displayed. - * Defaults to true. - */ - hasExecutionOrder?: boolean; - - /** - * The order in which this cell was executed. - */ - executionOrder?: number; - - /** - * A status message to be shown in the cell's status bar - */ - // todo@API duplicates status bar API - statusMessage?: string; - - /** - * The cell's current run state - */ - runState?: NotebookCellRunState; - - /** - * If the cell is running, the time at which the cell started running - */ - runStartTime?: number; - - /** - * The total duration of the cell's last run - */ - // todo@API depends on having output - lastRunDuration?: number; - } - export interface NotebookKernel { readonly id?: string; label: string; diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 32d13f792e0..155c978701a 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -1273,6 +1273,12 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I // checkProposedApiEnabled(extension); return extHostTypes.NotebookCellRunState; }, + get NotebookDocumentMetadata() { + return extHostTypes.NotebookDocumentMetadata; + }, + get NotebookCellMetadata() { + return extHostTypes.NotebookCellMetadata; + }, get NotebookRunState() { // checkProposedApiEnabled(extension); return extHostTypes.NotebookRunState; diff --git a/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts index 04a5cd56a2c..e6ba271e43d 100644 --- a/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -714,23 +714,31 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN } const that = this; - const document = new ExtHostNotebookDocument(this._documentsAndEditors, { - emitModelChange(event: vscode.NotebookCellsChangeEvent): void { - that._onDidChangeNotebookCells.fire(event); + const document = new ExtHostNotebookDocument( + this._documentsAndEditors, + { + emitModelChange(event: vscode.NotebookCellsChangeEvent): void { + that._onDidChangeNotebookCells.fire(event); + }, + emitCellOutputsChange(event: vscode.NotebookCellOutputsChangeEvent): void { + that._onDidChangeCellOutputs.fire(event); + }, + emitCellLanguageChange(event: vscode.NotebookCellLanguageChangeEvent): void { + that._onDidChangeCellLanguage.fire(event); + }, + emitCellMetadataChange(event: vscode.NotebookCellMetadataChangeEvent): void { + that._onDidChangeCellMetadata.fire(event); + }, + emitDocumentMetadataChange(event: vscode.NotebookDocumentMetadataChangeEvent): void { + that._onDidChangeNotebookDocumentMetadata.fire(event); + } }, - emitCellOutputsChange(event: vscode.NotebookCellOutputsChangeEvent): void { - that._onDidChangeCellOutputs.fire(event); - }, - emitCellLanguageChange(event: vscode.NotebookCellLanguageChangeEvent): void { - that._onDidChangeCellLanguage.fire(event); - }, - emitCellMetadataChange(event: vscode.NotebookCellMetadataChangeEvent): void { - that._onDidChangeCellMetadata.fire(event); - }, - emitDocumentMetadataChange(event: vscode.NotebookDocumentMetadataChangeEvent): void { - that._onDidChangeNotebookDocumentMetadata.fire(event); - } - }, viewType, modelData.contentOptions, typeConverters.NotebookDocumentMetadata.to(modelData.metadata ?? {}), uri, storageRoot); + viewType, + modelData.contentOptions, + modelData.metadata ? typeConverters.NotebookDocumentMetadata.to(modelData.metadata) : new extHostTypes.NotebookDocumentMetadata(), + uri, + storageRoot + ); document.acceptModelChanged({ versionId: modelData.versionId, diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 039418367df..1c0301a8ac2 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -1418,7 +1418,7 @@ export namespace NotebookCellRange { export namespace NotebookCellMetadata { - export function to(data: vscode.NotebookCellMetadata): types.NotebookCellMetadata { + export function to(data: notebooks.NotebookCellMetadata): types.NotebookCellMetadata { return new types.NotebookCellMetadata(data.editable, data.breakpointMargin, data.runnable, data.hasExecutionOrder, data.executionOrder, data.runStartTime, data.runStartTime, data.statusMessage, data.lastRunDuration, data.inputCollapsed, data.outputCollapsed, data.custom); } } @@ -1429,7 +1429,7 @@ export namespace NotebookDocumentMetadata { return data; } - export function to(data: vscode.NotebookDocumentMetadata): types.NotebookDocumentMetadata { + export function to(data: notebooks.NotebookDocumentMetadata): types.NotebookDocumentMetadata { return new types.NotebookDocumentMetadata(data.editable, data.runnable, data.cellEditable, data.cellRunnable, data.cellHasExecutionOrder, data.displayOrder, data.custom, data.runState, data.trusted); } From 5daa0b3b59f436b7c71e809754f0d0c32d88c27d Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 17 Feb 2021 05:53:01 -0800 Subject: [PATCH 253/325] Fix right click paste Fixes #116801 Fixes #116850 --- src/vs/workbench/contrib/terminal/browser/terminalView.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalView.ts b/src/vs/workbench/contrib/terminal/browser/terminalView.ts index 3e3dafe4c3c..1137b074694 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalView.ts @@ -245,10 +245,10 @@ export class TerminalViewPane extends ViewPane { await terminal.copySelection(); terminal.clearSelection(); } else { - if (!BrowserFeatures.clipboard.readText) { + if (BrowserFeatures.clipboard.readText) { terminal.paste(); } else { - this._notificationService.info('This browser doesn\'t support the clipboard.readText API needed to trigger a paste'); + this._notificationService.info(`This browser doesn\'t support the clipboard.readText API needed to trigger a paste, try ${platform.isMacintosh ? '⌘' : 'Ctrl'}+V instead.`); } } // Clear selection after all click event bubbling is finished on Mac to prevent From 797dc143ffbb994b0b8daeb359d49603492829e3 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru Date: Wed, 17 Feb 2021 14:40:51 +0100 Subject: [PATCH 254/325] Fixed command, added spacing --- src/vs/workbench/browser/actions/workspaceActions.ts | 8 ++++---- .../contrib/workspace/browser/workspace.contribution.ts | 2 +- .../contrib/workspace/browser/workspaceTrustEditor.css | 4 ++++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts index 713e088b96f..bc4fcc35b0e 100644 --- a/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -258,13 +258,13 @@ class WorkspaceTrustManageAction extends Action2 { title: { value: nls.localize('manageTrustAction', "Manage Workspace Trust"), original: 'Manage Workspace Trust' }, precondition: ContextKeyExpr.equals(`config.${WORKSPACE_TRUST_ENABLED}`, true), category: nls.localize('workspacesCategory', "Workspaces"), - f1: true, + f1: true }); } - run(accessor: ServicesAccessor) { - const editorService = accessor.get(IEditorService); - editorService.openEditor({ resource: WORKSPACE_TRUST_URI, mode: 'jsonc', options: { pinned: true } }); + async run(accessor: ServicesAccessor) { + const commandService = accessor.get(ICommandService); + await commandService.executeCommand('workbench.trust.manage'); } } diff --git a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts index d88325ffb9c..e2dd65d8c7e 100644 --- a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts +++ b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts @@ -308,7 +308,7 @@ registerAction2(class extends Action2 { const input = instantiationService.createInstance(WorkspaceTrustEditorInput); - editorService.openEditor(input); + editorService.openEditor(input, { pinned: true }); return; } }); diff --git a/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css index 03bfb124126..45ec02a5da4 100644 --- a/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css +++ b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css @@ -77,6 +77,10 @@ padding-right: 0; } +.workspace-trust-editor.settings-editor > .settings-body .settings-tree-container .monaco-list-row .monaco-tl-contents .setting-list-edit-row { + margin-top: 4px; +} + .workspace-trust-editor.settings-editor > .settings-body .settings-tree-container .monaco-list-row .monaco-tl-contents .setting-list-edit-row > .setting-list-valueInput { width: 100%; max-width: 100%; From d7230651accb198f5936ecae34fef387ee1023a7 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru Date: Wed, 17 Feb 2021 14:58:33 +0100 Subject: [PATCH 255/325] Remove old workspace trust editor --- .../browser/actions/workspaceActions.ts | 2 +- .../browser/workspace.contribution.ts | 11 +-- .../workspaceTrustFileSystemProvider.ts | 86 ------------------- .../workspaces/common/workspaceTrust.ts | 2 +- 4 files changed, 3 insertions(+), 98 deletions(-) delete mode 100644 src/vs/workbench/contrib/workspace/common/workspaceTrustFileSystemProvider.ts diff --git a/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts index bc4fcc35b0e..8817e5fd820 100644 --- a/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -23,7 +23,7 @@ import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IWorkspacesService, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; -import { WORKSPACE_TRUST_ENABLED, WORKSPACE_TRUST_URI } from 'vs/workbench/services/workspaces/common/workspaceTrust'; +import { WORKSPACE_TRUST_ENABLED } from 'vs/workbench/services/workspaces/common/workspaceTrust'; export class OpenFileAction extends Action { diff --git a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts index e2dd65d8c7e..196a3a79711 100644 --- a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts +++ b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts @@ -20,7 +20,6 @@ import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; import { Codicon } from 'vs/base/common/codicons'; import { ThemeColor } from 'vs/workbench/api/common/extHostTypes'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { WorkspaceTrustFileSystemProvider } from 'vs/workbench/contrib/workspace/common/workspaceTrustFileSystemProvider'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -178,14 +177,6 @@ Registry.as(WorkbenchExtensions.Workbench).regi LifecyclePhase.Starting ); -/* - * Trusted Workspace JSON Editor - */ -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution( - WorkspaceTrustFileSystemProvider, - LifecyclePhase.Ready -); - /** * Trusted Workspace GUI Editor */ @@ -308,7 +299,7 @@ registerAction2(class extends Action2 { const input = instantiationService.createInstance(WorkspaceTrustEditorInput); - editorService.openEditor(input, { pinned: true }); + editorService.openEditor(input, { pinned: true, revealIfOpened: true }); return; } }); diff --git a/src/vs/workbench/contrib/workspace/common/workspaceTrustFileSystemProvider.ts b/src/vs/workbench/contrib/workspace/common/workspaceTrustFileSystemProvider.ts deleted file mode 100644 index 4c4c49f9480..00000000000 --- a/src/vs/workbench/contrib/workspace/common/workspaceTrustFileSystemProvider.ts +++ /dev/null @@ -1,86 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Event } from 'vs/base/common/event'; -import { IDisposable } from 'vs/base/common/lifecycle'; -import { URI } from 'vs/base/common/uri'; -import { FileDeleteOptions, FileOverwriteOptions, FileSystemProviderCapabilities, FileType, FileWriteOptions, IFileService, IStat, IWatchOptions, IFileSystemProviderWithFileReadWriteCapability } from 'vs/platform/files/common/files'; -import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; -import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { VSBuffer } from 'vs/base/common/buffer'; -import { WORKSPACE_TRUST_STORAGE_KEY } from 'vs/workbench/services/workspaces/common/workspaceTrust'; - -const WORKSPACE_TRUST_SCHEMA = 'workspaceTrust'; - -const TRUSTED_WORKSPACES_STAT: IStat = { - type: FileType.File, - ctime: Date.now(), - mtime: Date.now(), - size: 0 -}; - -const PREPENDED_TEXT = `// The following file is a placeholder UX for managing trusted workspaces. It will be replaced by a rich editor and provide -// additonal information about what trust means. e.g. enabling trust will unblock automatic tasks on startup and list the tasks. It will enable certain extensions -// and list the extensions with associated functionality. -`; - -export class WorkspaceTrustFileSystemProvider implements IFileSystemProviderWithFileReadWriteCapability, IWorkbenchContribution { - readonly capabilities = FileSystemProviderCapabilities.FileReadWrite; - - readonly onDidChangeCapabilities = Event.None; - readonly onDidChangeFile = Event.None; - - constructor( - @IFileService private readonly fileService: IFileService, - @IStorageService private readonly storageService: IStorageService, - ) { - this.fileService.registerProvider(WORKSPACE_TRUST_SCHEMA, this); - } - - stat(resource: URI): Promise { - return Promise.resolve(TRUSTED_WORKSPACES_STAT); - } - - async readFile(resource: URI): Promise { - let workspacesTrustContent = this.storageService.get(WORKSPACE_TRUST_STORAGE_KEY, StorageScope.GLOBAL); - - let objectForm = {}; - try { - objectForm = JSON.parse(workspacesTrustContent || '{}'); - } catch { } - - const buffer = VSBuffer.fromString(PREPENDED_TEXT + JSON.stringify(objectForm, undefined, 2)).buffer; - return buffer; - } - - writeFile(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise { - try { - const workspacesTrustContent = VSBuffer.wrap(content).toString().replace(PREPENDED_TEXT, ''); - this.storageService.store(WORKSPACE_TRUST_STORAGE_KEY, workspacesTrustContent, StorageScope.GLOBAL, StorageTarget.MACHINE); - } catch (err) { } - - return Promise.resolve(); - } - - watch(resource: URI, opts: IWatchOptions): IDisposable { - return { - dispose() { - return; - } - }; - } - mkdir(resource: URI): Promise { - return Promise.resolve(undefined!); - } - readdir(resource: URI): Promise<[string, FileType][]> { - return Promise.resolve(undefined!); - } - delete(resource: URI, opts: FileDeleteOptions): Promise { - return Promise.resolve(undefined!); - } - rename(from: URI, to: URI, opts: FileOverwriteOptions): Promise { - return Promise.resolve(undefined!); - } -} diff --git a/src/vs/workbench/services/workspaces/common/workspaceTrust.ts b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts index 192c25c7aed..b9ec07aeeeb 100644 --- a/src/vs/workbench/services/workspaces/common/workspaceTrust.ts +++ b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts @@ -17,7 +17,7 @@ import { EditorModel } from 'vs/workbench/common/editor'; export const WORKSPACE_TRUST_ENABLED = 'workspace.trustEnabled'; export const WORKSPACE_TRUST_STORAGE_KEY = 'content.trust.model.key'; -export const WORKSPACE_TRUST_URI = URI.parse('workspaceTrust:/Trusted Workspaces'); +//export const WORKSPACE_TRUST_URI = URI.parse('workspaceTrust:/Trusted Workspaces'); export const WorkspaceTrustContext = { PendingRequest: new RawContextKey('workspaceTrustPendingRequest', false), From 9de38fc9a8058f0b42057bb0076d989455b58edc Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 17 Feb 2021 15:09:40 +0100 Subject: [PATCH 256/325] Disable keytar in our integration tests (#116852) * tests - extract and use ALL_PLATFORMS_API_TESTS_EXTRA_ARGS * tests - throw when accessing keytar from API tests --- scripts/test-integration.bat | 18 ++++++++++-------- scripts/test-integration.sh | 19 +++++++++++-------- src/vs/platform/environment/common/argv.ts | 1 + .../electron-main/environmentMainService.ts | 4 ++++ src/vs/platform/environment/node/argv.ts | 1 + .../electron-main/nativeHostMainService.ts | 18 +++++++++++++----- test/automation/src/code.ts | 1 + 7 files changed, 41 insertions(+), 21 deletions(-) diff --git a/scripts/test-integration.bat b/scripts/test-integration.bat index 3013dc04b90..3f8390b0b2b 100644 --- a/scripts/test-integration.bat +++ b/scripts/test-integration.bat @@ -45,31 +45,33 @@ if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" ( :: Tests in the extension host -call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% +set ALL_PLATFORMS_API_TESTS_EXTRA_ARGS=--disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-keytar --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% + +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests %ALL_PLATFORMS_API_TESTS_EXTRA_ARGS% if %errorlevel% neq 0 exit /b %errorlevel% -call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests %ALL_PLATFORMS_API_TESTS_EXTRA_ARGS% if %errorlevel% neq 0 exit /b %errorlevel% -call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-colorize-tests\test --extensionDevelopmentPath=%~dp0\..\extensions\vscode-colorize-tests --extensionTestsPath=%~dp0\..\extensions\vscode-colorize-tests\out --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-colorize-tests\test --extensionDevelopmentPath=%~dp0\..\extensions\vscode-colorize-tests --extensionTestsPath=%~dp0\..\extensions\vscode-colorize-tests\out %ALL_PLATFORMS_API_TESTS_EXTRA_ARGS% if %errorlevel% neq 0 exit /b %errorlevel% -call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\typescript-language-features\test-workspace --extensionDevelopmentPath=%~dp0\..\extensions\typescript-language-features --extensionTestsPath=%~dp0\..\extensions\typescript-language-features\out\test\unit --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\typescript-language-features\test-workspace --extensionDevelopmentPath=%~dp0\..\extensions\typescript-language-features --extensionTestsPath=%~dp0\..\extensions\typescript-language-features\out\test\unit %ALL_PLATFORMS_API_TESTS_EXTRA_ARGS% if %errorlevel% neq 0 exit /b %errorlevel% -call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\markdown-language-features\test-workspace --extensionDevelopmentPath=%~dp0\..\extensions\markdown-language-features --extensionTestsPath=%~dp0\..\extensions\markdown-language-features\out\test --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\markdown-language-features\test-workspace --extensionDevelopmentPath=%~dp0\..\extensions\markdown-language-features --extensionTestsPath=%~dp0\..\extensions\markdown-language-features\out\test %ALL_PLATFORMS_API_TESTS_EXTRA_ARGS% if %errorlevel% neq 0 exit /b %errorlevel% -call "%INTEGRATION_TEST_ELECTRON_PATH%" $%~dp0\..\extensions\emmet\out\test\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% . +call "%INTEGRATION_TEST_ELECTRON_PATH%" $%~dp0\..\extensions\emmet\out\test\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test %ALL_PLATFORMS_API_TESTS_EXTRA_ARGS% . if %errorlevel% neq 0 exit /b %errorlevel% -call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-notebook-tests\test --enable-proposed-api=vscode.vscode-notebook-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-notebook-tests --extensionTestsPath=%~dp0\..\extensions\vscode-notebook-tests\out --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-notebook-tests\test --enable-proposed-api=vscode.vscode-notebook-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-notebook-tests --extensionTestsPath=%~dp0\..\extensions\vscode-notebook-tests\out %ALL_PLATFORMS_API_TESTS_EXTRA_ARGS% if %errorlevel% neq 0 exit /b %errorlevel% for /f "delims=" %%i in ('node -p "require('fs').realpathSync.native(require('os').tmpdir())"') do set TEMPDIR=%%i set GITWORKSPACE=%TEMPDIR%\git-%RANDOM% mkdir %GITWORKSPACE% -call "%INTEGRATION_TEST_ELECTRON_PATH%" %GITWORKSPACE% --extensionDevelopmentPath=%~dp0\..\extensions\git --extensionTestsPath=%~dp0\..\extensions\git\out\test --enable-proposed-api=vscode.git --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% +call "%INTEGRATION_TEST_ELECTRON_PATH%" %GITWORKSPACE% --extensionDevelopmentPath=%~dp0\..\extensions\git --extensionTestsPath=%~dp0\..\extensions\git\out\test --enable-proposed-api=vscode.git %ALL_PLATFORMS_API_TESTS_EXTRA_ARGS% if %errorlevel% neq 0 exit /b %errorlevel% :: Tests in commonJS (CSS, HTML) diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index 537347a6dba..0eeefd80bff 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -65,28 +65,31 @@ fi after_suite # Tests in the extension host -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR + +ALL_PLATFORMS_API_TESTS_EXTRA_ARGS="--disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-keytar --disable-extensions --user-data-dir=$VSCODEUSERDATADIR" + +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests $ALL_PLATFORMS_API_TESTS_EXTRA_ARGS after_suite -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests $ALL_PLATFORMS_API_TESTS_EXTRA_ARGS after_suite -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out $ALL_PLATFORMS_API_TESTS_EXTRA_ARGS after_suite -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/markdown-language-features/test-workspace --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/markdown-language-features/test-workspace --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test $ALL_PLATFORMS_API_TESTS_EXTRA_ARGS after_suite -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/typescript-language-features/test-workspace --extensionDevelopmentPath=$ROOT/extensions/typescript-language-features --extensionTestsPath=$ROOT/extensions/typescript-language-features/out/test/unit --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/typescript-language-features/test-workspace --extensionDevelopmentPath=$ROOT/extensions/typescript-language-features --extensionTestsPath=$ROOT/extensions/typescript-language-features/out/test/unit $ALL_PLATFORMS_API_TESTS_EXTRA_ARGS after_suite -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/emmet/out/test/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/emmet/out/test/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test $ALL_PLATFORMS_API_TESTS_EXTRA_ARGS after_suite -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $(mktemp -d 2>/dev/null) --enable-proposed-api=vscode.git --extensionDevelopmentPath=$ROOT/extensions/git --extensionTestsPath=$ROOT/extensions/git/out/test --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $(mktemp -d 2>/dev/null) --enable-proposed-api=vscode.git --extensionDevelopmentPath=$ROOT/extensions/git --extensionTestsPath=$ROOT/extensions/git/out/test $ALL_PLATFORMS_API_TESTS_EXTRA_ARGS after_suite -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-notebook-tests/test --enable-proposed-api=vscode.vscode-notebook-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-notebook-tests --extensionTestsPath=$ROOT/extensions/vscode-notebook-tests/out/ --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-notebook-tests/test --enable-proposed-api=vscode.vscode-notebook-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-notebook-tests --extensionTestsPath=$ROOT/extensions/vscode-notebook-tests/out/ $ALL_PLATFORMS_API_TESTS_EXTRA_ARGS after_suite # Tests in commonJS (CSS, HTML) diff --git a/src/vs/platform/environment/common/argv.ts b/src/vs/platform/environment/common/argv.ts index 019410e6a30..d36a3dfc49c 100644 --- a/src/vs/platform/environment/common/argv.ts +++ b/src/vs/platform/environment/common/argv.ts @@ -63,6 +63,7 @@ export interface NativeParsedArgs { 'export-default-configuration'?: string; 'install-source'?: string; 'disable-updates'?: boolean; + 'disable-keytar'?: boolean; 'disable-crash-reporter'?: boolean; 'crash-reporter-directory'?: string; 'crash-reporter-id'?: string; diff --git a/src/vs/platform/environment/electron-main/environmentMainService.ts b/src/vs/platform/environment/electron-main/environmentMainService.ts index 35b09d89d39..49acc89b969 100644 --- a/src/vs/platform/environment/electron-main/environmentMainService.ts +++ b/src/vs/platform/environment/electron-main/environmentMainService.ts @@ -36,6 +36,7 @@ export interface IEnvironmentMainService extends INativeEnvironmentService { sandbox: boolean; driverVerbose: boolean; disableUpdates: boolean; + disableKeytar: boolean; } export class EnvironmentMainService extends NativeEnvironmentService implements IEnvironmentMainService { @@ -61,6 +62,9 @@ export class EnvironmentMainService extends NativeEnvironmentService implements @memoize get disableUpdates(): boolean { return !!this._args['disable-updates']; } + @memoize + get disableKeytar(): boolean { return !!this._args['disable-keytar']; } + @memoize get nodeCachedDataDir(): string | undefined { return process.env['VSCODE_NODE_CACHED_DATA_DIR'] || undefined; } } diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index 7b6a60b5728..6f532262ae0 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -95,6 +95,7 @@ export const OPTIONS: OptionDescriptions> = { 'skip-release-notes': { type: 'boolean' }, 'disable-telemetry': { type: 'boolean' }, 'disable-updates': { type: 'boolean' }, + 'disable-keytar': { type: 'boolean' }, 'disable-crash-reporter': { type: 'boolean' }, 'crash-reporter-directory': { type: 'string' }, 'crash-reporter-id': { type: 'string' }, diff --git a/src/vs/platform/native/electron-main/nativeHostMainService.ts b/src/vs/platform/native/electron-main/nativeHostMainService.ts index ba9d54e54fd..989cf596f6f 100644 --- a/src/vs/platform/native/electron-main/nativeHostMainService.ts +++ b/src/vs/platform/native/electron-main/nativeHostMainService.ts @@ -658,7 +658,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain private static readonly PASSWORD_CHUNK_SIZE = NativeHostMainService.MAX_PASSWORD_LENGTH - 100; async getPassword(windowId: number | undefined, service: string, account: string): Promise { - const keytar = await import('keytar'); + const keytar = await this.withKeytar(); const password = await keytar.getPassword(service, account); if (password) { @@ -686,7 +686,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain } async setPassword(windowId: number | undefined, service: string, account: string, password: string): Promise { - const keytar = await import('keytar'); + const keytar = await this.withKeytar(); if (isWindows && password.length > NativeHostMainService.MAX_PASSWORD_LENGTH) { let index = 0; @@ -714,7 +714,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain } async deletePassword(windowId: number | undefined, service: string, account: string): Promise { - const keytar = await import('keytar'); + const keytar = await this.withKeytar(); const didDelete = await keytar.deletePassword(service, account); if (didDelete) { @@ -725,17 +725,25 @@ export class NativeHostMainService extends Disposable implements INativeHostMain } async findPassword(windowId: number | undefined, service: string): Promise { - const keytar = await import('keytar'); + const keytar = await this.withKeytar(); return keytar.findPassword(service); } async findCredentials(windowId: number | undefined, service: string): Promise> { - const keytar = await import('keytar'); + const keytar = await this.withKeytar(); return keytar.findCredentials(service); } + private async withKeytar(): Promise { + if (this.environmentMainService.disableKeytar) { + throw new Error('keytar has been disabled via --disable-keytar option'); + } + + return await import('keytar'); + } + //#endregion private windowById(windowId: number | undefined): ICodeWindow | undefined { diff --git a/test/automation/src/code.ts b/test/automation/src/code.ts index 0f04f08fa26..719598b188e 100644 --- a/test/automation/src/code.ts +++ b/test/automation/src/code.ts @@ -138,6 +138,7 @@ export async function spawn(options: SpawnOptions): Promise { '--disable-telemetry', '--no-cached-data', '--disable-updates', + '--disable-keytar', '--disable-crash-reporter', `--extensions-dir=${options.extensionsPath}`, `--user-data-dir=${options.userDataDir}`, From 154c94ef3b10241381b3f665abb7a52a71cf7b7a Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 17 Feb 2021 06:14:36 -0800 Subject: [PATCH 257/325] Update terminalView.ts --- src/vs/workbench/contrib/terminal/browser/terminalView.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalView.ts b/src/vs/workbench/contrib/terminal/browser/terminalView.ts index 1137b074694..fa6cbfcab7d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalView.ts @@ -248,7 +248,7 @@ export class TerminalViewPane extends ViewPane { if (BrowserFeatures.clipboard.readText) { terminal.paste(); } else { - this._notificationService.info(`This browser doesn\'t support the clipboard.readText API needed to trigger a paste, try ${platform.isMacintosh ? '⌘' : 'Ctrl'}+V instead.`); + this._notificationService.info(`This browser doesn't support the clipboard.readText API needed to trigger a paste, try ${platform.isMacintosh ? '⌘' : 'Ctrl'}+V instead.`); } } // Clear selection after all click event bubbling is finished on Mac to prevent From 29f80fb60f64e1bba5087190faffc229ad117aba Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 17 Feb 2021 15:21:14 +0100 Subject: [PATCH 258/325] :up: distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1669245e977..2b3c52ca0bd 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.54.0", - "distro": "59d93479b4a5c88173a91fec50e348126e94a818", + "distro": "1817e827de94819a2303cf0b7a17ae5cc7dfbb80", "author": { "name": "Microsoft Corporation" }, From 79f90304beb5ec2c4c90688e6b0c61e8bd80595b Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 17 Feb 2021 15:21:18 +0100 Subject: [PATCH 259/325] refine completion provider for context keys, https://github.com/microsoft/vscode/issues/9303 --- .../src/configurationEditingMain.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/extensions/configuration-editing/src/configurationEditingMain.ts b/extensions/configuration-editing/src/configurationEditingMain.ts index f4c2ab34174..28bcda61df2 100644 --- a/extensions/configuration-editing/src/configurationEditingMain.ts +++ b/extensions/configuration-editing/src/configurationEditingMain.ts @@ -147,17 +147,22 @@ function registerContextKeyCompletions(): vscode.Disposable { { async provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken) { - const replacing = document.getWordRangeAtPosition(position, /[\w.-\d]/); - const inserting = replacing?.with(undefined, position); - if (!replacing || !inserting) { + const location = getLocation(document.getText(), document.offsetAt(position)); + + if (location.isAtPropertyKey) { return; } - const location = getLocation(document.getText(), document.offsetAt(position)); if (!location.matches(['*', 'when']) && !location.matches(['contributes', 'menus', '*', '*', 'when'])) { return; } + const replacing = document.getWordRangeAtPosition(position, /[^"\s]+/); + if (!replacing) { + return; + } + const inserting = replacing.with(undefined, position); + const data = await vscode.commands.executeCommand('getContextKeyInfo'); if (token.isCancellationRequested || !data) { return; From 6ecae6f5f946c925b01aec7422fdbc0cfd1c9bd3 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 17 Feb 2021 15:39:35 +0100 Subject: [PATCH 260/325] shared process - log errors properly --- src/vs/code/electron-main/app.ts | 23 ++++++++-- .../electron-main/sharedProcess.ts | 18 +++++--- .../platform/windows/electron-main/window.ts | 43 +++++++++++-------- .../platform/windows/electron-main/windows.ts | 18 ++++++++ 4 files changed, 74 insertions(+), 28 deletions(-) diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 4d17030027a..d6a819dee64 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -37,7 +37,7 @@ import product from 'vs/platform/product/common/product'; import { ProxyAuthHandler } from 'vs/code/electron-main/auth'; import { FileProtocolHandler } from 'vs/code/electron-main/protocol'; import { Disposable } from 'vs/base/common/lifecycle'; -import { IWindowsMainService, ICodeWindow, OpenContext } from 'vs/platform/windows/electron-main/windows'; +import { IWindowsMainService, ICodeWindow, OpenContext, WindowError } from 'vs/platform/windows/electron-main/windows'; import { URI } from 'vs/base/common/uri'; import { hasWorkspaceFileExtension, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { WorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService'; @@ -465,7 +465,7 @@ export class CodeApplication extends Disposable { const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor, mainProcessElectronServer, fileProtocolHandler)); // Post Open Windows Tasks - appInstantiationService.invokeFunction(accessor => this.afterWindowOpen(accessor)); + appInstantiationService.invokeFunction(accessor => this.afterWindowOpen(accessor, sharedProcess)); // Tracing: Stop tracing after windows are ready if enabled if (this.environmentMainService.args.trace) { @@ -926,11 +926,28 @@ export class CodeApplication extends Disposable { return { fileUri: URI.file(path) }; } - private async afterWindowOpen(accessor: ServicesAccessor): Promise { + private async afterWindowOpen(accessor: ServicesAccessor, sharedProcess: SharedProcess): Promise { // Signal phase: after window open this.lifecycleMainService.phase = LifecycleMainPhase.AfterWindowOpen; + // Observe shared process for errors + const telemetryService = accessor.get(ITelemetryService); + this._register(sharedProcess.onDidError(e => { + + // Logging + onUnexpectedError(new Error(e.message)); + + // Telemetry + type SharedProcessErrorClassification = { + type: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + }; + type SharedProcessErrorEvent = { + type: WindowError; + }; + telemetryService.publicLog2('sharedprocesserror', { type: e.type }); + })); + // Windows: install mutex const win32MutexName = product.win32MutexName; if (isWindows && win32MutexName) { diff --git a/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts b/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts index 889a2c3b85f..8c40cb0f9c3 100644 --- a/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts +++ b/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { BrowserWindow, ipcMain, Event, MessagePortMain } from 'electron'; +import { BrowserWindow, ipcMain, Event as ElectronEvent, MessagePortMain } from 'electron'; import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService'; import { Barrier } from 'vs/base/common/async'; import { ILogService } from 'vs/platform/log/common/log'; @@ -15,14 +15,18 @@ import { ISharedProcess, ISharedProcessConfiguration } from 'vs/platform/sharedP import { Disposable } from 'vs/base/common/lifecycle'; import { connect as connectMessagePort } from 'vs/base/parts/ipc/electron-main/ipc.mp'; import { assertIsDefined } from 'vs/base/common/types'; -import { onUnexpectedError } from 'vs/base/common/errors'; +import { Emitter, Event } from 'vs/base/common/event'; +import { WindowError } from 'vs/platform/windows/electron-main/windows'; export class SharedProcess extends Disposable implements ISharedProcess { private readonly whenSpawnedBarrier = new Barrier(); private window: BrowserWindow | undefined = undefined; - private windowCloseListener: ((event: Event) => void) | undefined = undefined; + private windowCloseListener: ((event: ElectronEvent) => void) | undefined = undefined; + + private readonly _onDidError = this._register(new Emitter<{ type: WindowError, message: string }>()); + readonly onDidError = Event.buffer(this._onDidError.event); // buffer until we have a listener! constructor( private readonly machineId: string, @@ -187,7 +191,7 @@ export class SharedProcess extends Disposable implements ISharedProcess { } // Prevent the window from closing - this.windowCloseListener = (e: Event) => { + this.windowCloseListener = (e: ElectronEvent) => { this.logService.trace('SharedProcess#close prevented'); // We never allow to close the shared process unless we get explicitly disposed() @@ -204,9 +208,9 @@ export class SharedProcess extends Disposable implements ISharedProcess { // Crashes & Unrsponsive & Failed to load // We use `onUnexpectedError` explicitly because the error handler // will send the error to the active window to log in devtools too - this.window.webContents.on('render-process-gone', (event, details) => onUnexpectedError(new Error(`SharedProcess: crashed (detail: ${details?.reason})`))); - this.window.on('unresponsive', () => onUnexpectedError(new Error('SharedProcess: detected unresponsive window'))); - this.window.webContents.on('did-fail-load', (event, errorCode, errorDescription) => onUnexpectedError(new Error(`SharedProcess: failed to load window: ${errorDescription}`))); + this.window.webContents.on('render-process-gone', (event, details) => this._onDidError.fire({ type: WindowError.CRASHED, message: `SharedProcess: crashed (detail: ${details?.reason})` })); + this.window.on('unresponsive', () => this._onDidError.fire({ type: WindowError.UNRESPONSIVE, message: 'SharedProcess: detected unresponsive window' })); + this.window.webContents.on('did-fail-load', (event, errorCode, errorDescription) => this._onDidError.fire({ type: WindowError.LOAD, message: `SharedProcess: failed to load window: ${errorDescription}` })); } spawn(userEnv: NodeJS.ProcessEnv): void { diff --git a/src/vs/platform/windows/electron-main/window.ts b/src/vs/platform/windows/electron-main/window.ts index c386a584857..a68581665d7 100644 --- a/src/vs/platform/windows/electron-main/window.ts +++ b/src/vs/platform/windows/electron-main/window.ts @@ -9,7 +9,7 @@ import { localize } from 'vs/nls'; import { getMarks, mark } from 'vs/base/common/performance'; import { Emitter } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; -import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage, Rectangle, Display, TouchBarSegmentedControl, NativeImage, BrowserWindowConstructorOptions, SegmentedControlSegment, nativeTheme, Event, RenderProcessGoneDetails } from 'electron'; +import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage, Rectangle, Display, TouchBarSegmentedControl, NativeImage, BrowserWindowConstructorOptions, SegmentedControlSegment, nativeTheme, Event } from 'electron'; import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService'; import { ILogService } from 'vs/platform/log/common/log'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -19,7 +19,7 @@ import product from 'vs/platform/product/common/product'; import { WindowMinimumSize, IWindowSettings, MenuBarVisibility, getTitleBarStyle, getMenuBarVisibility, zoomLevelToZoomFactor, INativeWindowConfiguration } from 'vs/platform/windows/common/windows'; import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; import { browserCodeLoadingCacheStrategy, isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; -import { defaultWindowState, ICodeWindow, ILoadEvent, IWindowState, WindowMode } from 'vs/platform/windows/electron-main/windows'; +import { defaultWindowState, ICodeWindow, ILoadEvent, IWindowState, WindowError, WindowMode } from 'vs/platform/windows/electron-main/windows'; import { ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { IWorkspacesManagementMainService } from 'vs/platform/workspaces/electron-main/workspacesManagementMainService'; import { IBackupMainService } from 'vs/platform/backup/electron-main/backup'; @@ -48,11 +48,6 @@ interface ITouchBarSegment extends SegmentedControlSegment { id: string; } -const enum WindowError { - UNRESPONSIVE = 1, - CRASHED = 2 -} - const enum ReadyState { /** @@ -403,9 +398,9 @@ export class CodeWindow extends Disposable implements ICodeWindow { private registerListeners(): void { // Crashes & Unrsponsive & Failed to load - this._win.webContents.on('render-process-gone', (event, details) => this.onWindowError(WindowError.CRASHED, details)); this._win.on('unresponsive', () => this.onWindowError(WindowError.UNRESPONSIVE)); - this._win.webContents.on('did-fail-load', (event, errorCode, errorDescription) => this.logService.warn('Main: failed to load workbench window, ', errorDescription)); + this._win.webContents.on('render-process-gone', (event, details) => this.onWindowError(WindowError.CRASHED, details.reason)); + this._win.webContents.on('did-fail-load', (event, errorCode, errorDescription) => this.onWindowError(WindowError.LOAD, errorDescription)); // Window close this._win.on('closed', () => { @@ -550,9 +545,21 @@ export class CodeWindow extends Disposable implements ICodeWindow { } private async onWindowError(error: WindowError.UNRESPONSIVE): Promise; - private async onWindowError(error: WindowError.CRASHED, details: RenderProcessGoneDetails): Promise; - private async onWindowError(error: WindowError, details?: RenderProcessGoneDetails): Promise { - this.logService.error(error === WindowError.CRASHED ? `Main: renderer process crashed (detail: ${details?.reason})` : 'Main: detected unresponsive'); + private async onWindowError(error: WindowError.CRASHED, details: string): Promise; + private async onWindowError(error: WindowError.LOAD, details: string): Promise; + private async onWindowError(type: WindowError, details?: string): Promise { + + switch (type) { + case WindowError.CRASHED: + this.logService.error(`CodeWindow: renderer process crashed (detail: ${details})`); + break; + case WindowError.UNRESPONSIVE: + this.logService.error('CodeWindow: detected unresponsive'); + break; + case WindowError.LOAD: + this.logService.error(`CodeWindow: failed to load workbench window: ${details}`); + break; + } // If we run extension tests from CLI, showing a dialog is not // very helpful in this case. Rather, we bring down the test run @@ -569,10 +576,10 @@ export class CodeWindow extends Disposable implements ICodeWindow { type WindowErrorEvent = { type: WindowError; }; - this.telemetryService.publicLog2('windowerror', { type: error }); + this.telemetryService.publicLog2('windowerror', { type }); // Unresponsive - if (error === WindowError.UNRESPONSIVE) { + if (type === WindowError.UNRESPONSIVE) { if (this.isExtensionDevelopmentHost || this.isExtensionTestHost || (this._win && this._win.webContents && this._win.webContents.isDevToolsOpened())) { // TODO@bpasero Workaround for https://github.com/microsoft/vscode/issues/56994 // In certain cases the window can report unresponsiveness because a breakpoint was hit @@ -606,12 +613,12 @@ export class CodeWindow extends Disposable implements ICodeWindow { } // Crashed - else { + else if (type === WindowError.CRASHED) { let message: string; - if (details && details.reason !== 'crashed') { - message = localize('appCrashedDetails', "The window has crashed (reason: '{0}')", details?.reason); + if (details && details !== 'crashed') { + message = localize('appCrashedDetails', "The window has crashed (reason: '{0}')", details); } else { - message = localize('appCrashed', "The window has crashed", details?.reason); + message = localize('appCrashed', "The window has crashed", details); } const result = await this.dialogMainService.showMessageBox({ diff --git a/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts index 5a1446b4c4f..96f92d28946 100644 --- a/src/vs/platform/windows/electron-main/windows.ts +++ b/src/vs/platform/windows/electron-main/windows.ts @@ -125,6 +125,24 @@ export interface ICodeWindow extends IDisposable { serializeWindowState(): IWindowState; } +export const enum WindowError { + + /** + * Maps to the `unresponsive` event on a `BrowserWindow`. + */ + UNRESPONSIVE = 1, + + /** + * Maps to the `render-proces-gone` event on a `WebContents`. + */ + CRASHED = 2, + + /** + * Maps to the `did-fail-load` event on a `WebContents`. + */ + LOAD = 3 +} + export const IWindowsMainService = createDecorator('windowsMainService'); export interface IWindowsCountChangedEvent { From 8e003e638047cc75e6078c46b8e7611778af972f Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 17 Feb 2021 06:45:01 -0800 Subject: [PATCH 261/325] Adopt description in terminal RawContextKeys Fixes #116853 --- .../contrib/terminal/common/terminal.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 1c9f51ea37c..e4ea96f5b74 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -15,40 +15,40 @@ import { IExtensionPointDescriptor } from 'vs/workbench/services/extensions/comm export const TERMINAL_VIEW_ID = 'terminal'; /** A context key that is set when there is at least one opened integrated terminal. */ -export const KEYBINDING_CONTEXT_TERMINAL_IS_OPEN = new RawContextKey('terminalIsOpen', false); +export const KEYBINDING_CONTEXT_TERMINAL_IS_OPEN = new RawContextKey('terminalIsOpen', false, true); /** A context key that is set when the integrated terminal has focus. */ -export const KEYBINDING_CONTEXT_TERMINAL_FOCUS = new RawContextKey('terminalFocus', false); +export const KEYBINDING_CONTEXT_TERMINAL_FOCUS = new RawContextKey('terminalFocus', false, 'Whether the terminal is focused'); export const KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE_KEY = 'terminalShellType'; /** A context key that is set to the detected shell for the most recently active terminal, this is set to the last known value when no terminals exist. */ -export const KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE = new RawContextKey(KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE_KEY, undefined); +export const KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE = new RawContextKey(KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE_KEY, undefined, { type: 'string', description: 'The shell type of the active terminal' }); -export const KEYBINDING_CONTEXT_TERMINAL_ALT_BUFFER_ACTIVE = new RawContextKey('terminalAltBufferActive', false); +export const KEYBINDING_CONTEXT_TERMINAL_ALT_BUFFER_ACTIVE = new RawContextKey('terminalAltBufferActive', false, true); /** A context key that is set when the integrated terminal does not have focus. */ export const KEYBINDING_CONTEXT_TERMINAL_NOT_FOCUSED = KEYBINDING_CONTEXT_TERMINAL_FOCUS.toNegated(); /** A context key that is set when the user is navigating the accessibility tree */ -export const KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS = new RawContextKey('terminalA11yTreeFocus', false); +export const KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS = new RawContextKey('terminalA11yTreeFocus', false, true); /** A keybinding context key that is set when the integrated terminal has text selected. */ -export const KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED = new RawContextKey('terminalTextSelected', false); +export const KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED = new RawContextKey('terminalTextSelected', false, 'Whether text is selected in the active terminal'); /** A keybinding context key that is set when the integrated terminal does not have text selected. */ export const KEYBINDING_CONTEXT_TERMINAL_TEXT_NOT_SELECTED = KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED.toNegated(); /** A context key that is set when the find widget in integrated terminal is visible. */ -export const KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE = new RawContextKey('terminalFindVisible', false); +export const KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE = new RawContextKey('terminalFindVisible', false, true); /** A context key that is set when the find widget in integrated terminal is not visible. */ export const KEYBINDING_CONTEXT_TERMINAL_FIND_NOT_VISIBLE = KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE.toNegated(); /** A context key that is set when the find widget find input in integrated terminal is focused. */ -export const KEYBINDING_CONTEXT_TERMINAL_FIND_INPUT_FOCUSED = new RawContextKey('terminalFindInputFocused', false); +export const KEYBINDING_CONTEXT_TERMINAL_FIND_INPUT_FOCUSED = new RawContextKey('terminalFindInputFocused', false, true); /** A context key that is set when the find widget in integrated terminal is focused. */ -export const KEYBINDING_CONTEXT_TERMINAL_FIND_FOCUSED = new RawContextKey('terminalFindFocused', false); +export const KEYBINDING_CONTEXT_TERMINAL_FIND_FOCUSED = new RawContextKey('terminalFindFocused', false, true); /** A context key that is set when the find widget find input in integrated terminal is not focused. */ export const KEYBINDING_CONTEXT_TERMINAL_FIND_INPUT_NOT_FOCUSED = KEYBINDING_CONTEXT_TERMINAL_FIND_INPUT_FOCUSED.toNegated(); -export const KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED = new RawContextKey('terminalProcessSupported', false); +export const KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED = new RawContextKey('terminalProcessSupported', false, 'Whether terminal processes can be launched'); export const IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY = 'terminal.integrated.isWorkspaceShellAllowed'; export const NEVER_MEASURE_RENDER_TIME_STORAGE_KEY = 'terminal.integrated.neverMeasureRenderTime'; From 43262ab61af183de17f9b0de41bec324a0632251 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru Date: Wed, 17 Feb 2021 15:57:34 +0100 Subject: [PATCH 262/325] Add editor input factory --- .../browser/workspace.contribution.ts | 19 +++++++++++++++++++ .../workspaces/common/workspaceTrust.ts | 1 - 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts index 196a3a79711..04237e078bd 100644 --- a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts +++ b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts @@ -29,6 +29,7 @@ import { IEditorRegistry, Extensions as EditorExtensions, EditorDescriptor } fro import { WorkspaceTrustEditor } from 'vs/workbench/contrib/workspace/browser/workspaceTrustEditor'; import { WorkspaceTrustEditorInput } from 'vs/workbench/services/workspaces/browser/workspaceTrustEditorInput'; import { WorkspaceTrustContext, WORKSPACE_TRUST_ENABLED } from 'vs/workbench/services/workspaces/common/workspaceTrust'; +import { EditorInput, Extensions as EditorInputExtensions, IEditorInputFactory, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor'; const workspaceTrustIcon = registerIcon('workspace-trust-icon', Codicon.shield, localize('workspaceTrustIcon', "Icon for workspace trust badge.")); @@ -180,6 +181,24 @@ Registry.as(WorkbenchExtensions.Workbench).regi /** * Trusted Workspace GUI Editor */ +class WorkspaceTrustEditorInputInputFactory implements IEditorInputFactory { + + canSerialize(editorInput: EditorInput): boolean { + return true; + } + + serialize(input: WorkspaceTrustEditorInput): string { + return '{}'; + } + + deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): WorkspaceTrustEditorInput { + return instantiationService.createInstance(WorkspaceTrustEditorInput); + } +} + +Registry.as(EditorInputExtensions.EditorInputFactories) + .registerEditorInputFactory(WorkspaceTrustEditorInput.ID, WorkspaceTrustEditorInputInputFactory); + Registry.as(EditorExtensions.Editors).registerEditor( EditorDescriptor.create( WorkspaceTrustEditor, diff --git a/src/vs/workbench/services/workspaces/common/workspaceTrust.ts b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts index b9ec07aeeeb..f048e4d411d 100644 --- a/src/vs/workbench/services/workspaces/common/workspaceTrust.ts +++ b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts @@ -17,7 +17,6 @@ import { EditorModel } from 'vs/workbench/common/editor'; export const WORKSPACE_TRUST_ENABLED = 'workspace.trustEnabled'; export const WORKSPACE_TRUST_STORAGE_KEY = 'content.trust.model.key'; -//export const WORKSPACE_TRUST_URI = URI.parse('workspaceTrust:/Trusted Workspaces'); export const WorkspaceTrustContext = { PendingRequest: new RawContextKey('workspaceTrustPendingRequest', false), From a94e67e5e1c3b3b46357dd92ec6ae09242d64429 Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Wed, 17 Feb 2021 16:32:10 +0100 Subject: [PATCH 263/325] InlineValues provide: merge and sort segments per line --- .../debug/browser/debugEditorContribution.ts | 48 +++++++++++++++---- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts index 346d7c395aa..57ffcf9ef3e 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts @@ -50,6 +50,11 @@ const MAX_NUM_INLINE_VALUES = 100; // JS Global scope can have 700+ entries. We const MAX_INLINE_DECORATOR_LENGTH = 150; // Max string length of each inline decorator when debugging. If exceeded ... is added const MAX_TOKENIZATION_LINE_LEN = 500; // If line is too long, then inline values for the line are skipped +class InlineSegment { + constructor(public column: number, public text: string) { + } +} + function createInlineValueDecoration(lineNumber: number, contentText: string, column = Constants.MAX_SAFE_SMALL_INTEGER): IDecorationOptions { // If decoratorText is too long, trim and add ellipses. This could happen for minified files with everything on a single line if (contentText.length > MAX_INLINE_DECORATOR_LENGTH) { @@ -579,14 +584,14 @@ export class DebugEditorContribution implements IDebugEditorContribution { if (InlineValuesProviderRegistry.has(model)) { - const findVariable = async (key: string): Promise => { + const findVariable = async (_key: string, caseSensitiveLookup: boolean): Promise => { const scopes = await stackFrame.getMostSpecificScopes(stackFrame.range); + const key = caseSensitiveLookup ? _key : _key.toLowerCase(); for (let scope of scopes) { const variables = await scope.getChildren(); - for (let v of variables) { - if (v.name === key) { - return v.value; - } + const found = variables.find(v => caseSensitiveLookup ? (v.name === key) : (v.name.toLowerCase() === key)); + if (found) { + return found.value; } } return undefined; @@ -601,24 +606,36 @@ export class DebugEditorContribution implements IDebugEditorContribution { allDecorations = []; + const lineDecorations = new Map(); + const promises = flatten(providers.map(provider => ranges.map(range => Promise.resolve(provider.provideInlineValues(model, range, ctx, token)).then(async (result) => { if (result) { for (let iv of result) { - let text: string; + + let text: string | undefined = undefined; switch (iv.type) { case 'text': text = iv.text; break; case 'variable': - const value = await findVariable(iv.variableName); - text = `${iv.variableName} = ${value}`; + const value = await findVariable(iv.variableName, iv.caseSensitiveLookup); + if (value) { + text = `${iv.variableName} = ${value}`; + } break; case 'expression': text = `eval(${iv.expression})`; break; } + if (text) { - allDecorations.push(createInlineValueDecoration(iv.range.startLineNumber, text, iv.range.startColumn)); + const line = iv.range.startLineNumber; + let lineSegments = lineDecorations.get(line); + if (!lineSegments) { + lineSegments = []; + lineDecorations.set(line, lineSegments); + } + lineSegments.push(new InlineSegment(range.startColumn, text)); } } } @@ -628,7 +645,18 @@ export class DebugEditorContribution implements IDebugEditorContribution { await Promise.all(promises); - } else { // one-size-fits-all strategy + // sort line segments and concatenate them into a decoration + + lineDecorations.forEach((segments, line) => { + if (segments.length > 0) { + segments = segments.sort((a, b) => a.column - b.column); + const text = segments.map(s => s.text).join(', '); + allDecorations.push(createInlineValueDecoration(line, text)); + } + }); + + } else { + // old "one-size-fits-all" strategy const scopes = await stackFrame.getMostSpecificScopes(stackFrame.range); // Get all top level variables in the scope chain From 83d540c4bfa345c7754f2c92a2eb47fac72aa505 Mon Sep 17 00:00:00 2001 From: rebornix Date: Wed, 17 Feb 2021 08:06:44 -0800 Subject: [PATCH 264/325] :lipstick: --- src/vs/workbench/api/browser/mainThreadNotebook.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts index f761a9fec14..ef5198afafe 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -556,8 +556,6 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo const result: INotebookKernel[] = []; const kernelsDto = await that._proxy.$provideNotebookKernels(handle, uri, token); for (const dto of kernelsDto) { - console.log('kerneldto', dto.providerHandle); - result.push({ id: dto.id, friendlyId: dto.friendlyId, From ab84845737684fa2416e1f244b2f0e8c6f01e2e0 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 17 Feb 2021 17:44:54 +0100 Subject: [PATCH 265/325] make 'editor/title/run'-menu generally available --- src/vs/workbench/api/common/menusExtensionPoint.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/workbench/api/common/menusExtensionPoint.ts b/src/vs/workbench/api/common/menusExtensionPoint.ts index 6360dadf550..7122754cfc6 100644 --- a/src/vs/workbench/api/common/menusExtensionPoint.ts +++ b/src/vs/workbench/api/common/menusExtensionPoint.ts @@ -46,8 +46,7 @@ const apiMenus: IAPIMenu[] = [ { key: 'editor/title/run', id: MenuId.EditorTitleRun, - description: localize('menus.editorTitleRun', "Run submenu inside the editor title menu"), - proposed: true + description: localize('menus.editorTitleRun', "Run submenu inside the editor title menu") }, { key: 'editor/context', From c65da0b1d6289d2247342362153b79ca770fcab3 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 17 Feb 2021 17:52:10 +0100 Subject: [PATCH 266/325] perf - init KeyboardLayoutMainService in parallel to window opening //cc @alexdima --- .../electron-main/keyboardLayoutMainService.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/keyboardLayout/electron-main/keyboardLayoutMainService.ts b/src/vs/platform/keyboardLayout/electron-main/keyboardLayoutMainService.ts index f28a15dca5c..f11db7ea10a 100644 --- a/src/vs/platform/keyboardLayout/electron-main/keyboardLayoutMainService.ts +++ b/src/vs/platform/keyboardLayout/electron-main/keyboardLayoutMainService.ts @@ -3,11 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as nativeKeymap from 'native-keymap'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IKeyboardLayoutData, IKeyboardLayoutMainService as ICommonKeyboardLayoutMainService } from 'vs/platform/keyboardLayout/common/keyboardLayoutMainService'; import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; -import * as nativeKeymap from 'native-keymap'; +import { ILifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; export const IKeyboardLayoutMainService = createDecorator('keyboardLayoutMainService'); @@ -23,10 +24,17 @@ export class KeyboardLayoutMainService extends Disposable implements ICommonKeyb private _initPromise: Promise | null; private _keyboardLayoutData: IKeyboardLayoutData | null; - constructor() { + constructor( + @ILifecycleMainService lifecycleMainService: ILifecycleMainService + ) { super(); this._initPromise = null; this._keyboardLayoutData = null; + + // perf: automatically trigger initialize after windows + // have opened so that we can do this work in parallel + // to the window load. + lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this._initialize()); } private _initialize(): Promise { From 108616d3590004ad20879903949f5d445be79998 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 17 Feb 2021 19:00:21 +0100 Subject: [PATCH 267/325] support switching settings sync services in web synchronise setting sync service type in web show necessary prompts when services are changed --- .../common/abstractSynchronizer.ts | 2 +- .../userDataSync/common/globalStateMerge.ts | 20 ++-- .../userDataSync/common/globalStateSync.ts | 100 +++++++++++++++--- .../common/userDataAutoSyncService.ts | 4 +- .../userDataSync/common/userDataSync.ts | 8 +- .../userDataSync/common/userDataSyncIpc.ts | 1 + .../common/userDataSyncService.ts | 8 +- .../common/userDataSyncStoreService.ts | 17 ++- .../common/userDataSyncStoreService.test.ts | 1 + .../contrib/update/browser/update.ts | 41 +++++-- .../userDataSync/browser/userDataSync.ts | 30 ++++-- .../sandbox.simpleservices.ts | 2 - .../services/userData/browser/userDataInit.ts | 57 ++++++++-- .../browser/userDataSyncWorkbenchService.ts | 28 +++++ .../userDataSync/common/userDataSync.ts | 3 + 15 files changed, 252 insertions(+), 70 deletions(-) diff --git a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts index b8be4d3be94..0124ffeab7d 100644 --- a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts +++ b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts @@ -34,7 +34,7 @@ type SyncSourceClassification = { source?: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; }; -function isSyncData(thing: any): thing is ISyncData { +export function isSyncData(thing: any): thing is ISyncData { if (thing && (thing.version !== undefined && typeof thing.version === 'number') && (thing.content !== undefined && typeof thing.content === 'string')) { diff --git a/src/vs/platform/userDataSync/common/globalStateMerge.ts b/src/vs/platform/userDataSync/common/globalStateMerge.ts index e519854a95b..cea1c3d6d9f 100644 --- a/src/vs/platform/userDataSync/common/globalStateMerge.ts +++ b/src/vs/platform/userDataSync/common/globalStateMerge.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as objects from 'vs/base/common/objects'; -import { IStorageValue } from 'vs/platform/userDataSync/common/userDataSync'; +import { IStorageValue, SYNC_SERVICE_URL_TYPE } from 'vs/platform/userDataSync/common/userDataSync'; import { IStringDictionary } from 'vs/base/common/collections'; import { ILogService } from 'vs/platform/log/common/log'; @@ -30,15 +30,17 @@ export function merge(localStorage: IStringDictionary, remoteStor const local: { added: IStringDictionary, removed: string[], updated: IStringDictionary } = { added: {}, removed: [], updated: {} }; const remote: IStringDictionary = objects.deepClone(remoteStorage); + const isFirstTimeSync = !baseStorage; + // Added in local for (const key of baseToLocal.added.values()) { - // Skip if local was not synced before and remote also has the key - // In this case, remote gets precedence - if (!baseStorage && baseToRemote.added.has(key)) { + // If syncing for first time remote value gets precedence always, + // except for sync service type key - local value takes precedence for this key + if (key !== SYNC_SERVICE_URL_TYPE && isFirstTimeSync && baseToRemote.added.has(key)) { continue; - } else { - remote[key] = localStorage[key]; } + + remote[key] = localStorage[key]; } // Updated in local @@ -70,6 +72,12 @@ export function merge(localStorage: IStringDictionary, remoteStor if (localValue && localValue.value === remoteValue.value) { continue; } + + // Local sync service type value takes precedence if syncing for first time + if (key === SYNC_SERVICE_URL_TYPE && isFirstTimeSync && baseToLocal.added.has(key)) { + continue; + } + if (localValue) { local.updated[key] = remoteValue; } else { diff --git a/src/vs/platform/userDataSync/common/globalStateSync.ts b/src/vs/platform/userDataSync/common/globalStateSync.ts index 8561db5aeeb..2e58f17ae95 100644 --- a/src/vs/platform/userDataSync/common/globalStateSync.ts +++ b/src/vs/platform/userDataSync/common/globalStateSync.ts @@ -5,7 +5,7 @@ import { IUserDataSyncStoreService, IUserDataSyncLogService, IGlobalState, SyncResource, IUserDataSynchroniser, IUserDataSyncResourceEnablementService, - IUserDataSyncBackupStoreService, ISyncResourceHandle, IStorageValue, USER_DATA_SYNC_SCHEME, IRemoteUserData, Change, ALL_SYNC_RESOURCES, getEnablementKey, SYNC_SERVICE_URL_TYPE + IUserDataSyncBackupStoreService, ISyncResourceHandle, IStorageValue, USER_DATA_SYNC_SCHEME, IRemoteUserData, Change, ALL_SYNC_RESOURCES, getEnablementKey, SYNC_SERVICE_URL_TYPE, UserDataSyncStoreType, IUserData, ISyncData, createSyncHeaders, UserDataSyncError, UserDataSyncErrorCode } from 'vs/platform/userDataSync/common/userDataSync'; import { VSBuffer } from 'vs/base/common/buffer'; import { Event } from 'vs/base/common/event'; @@ -15,7 +15,7 @@ import { IStringDictionary } from 'vs/base/common/collections'; import { edit } from 'vs/platform/userDataSync/common/content'; import { merge } from 'vs/platform/userDataSync/common/globalStateMerge'; import { parse } from 'vs/base/common/json'; -import { AbstractInitializer, AbstractSynchroniser, IAcceptResult, IMergeResult, IResourcePreview } from 'vs/platform/userDataSync/common/abstractSynchronizer'; +import { AbstractInitializer, AbstractSynchroniser, IAcceptResult, IMergeResult, IResourcePreview, isSyncData } from 'vs/platform/userDataSync/common/abstractSynchronizer'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { URI } from 'vs/base/common/uri'; @@ -24,6 +24,11 @@ import { applyEdits } from 'vs/base/common/jsonEdit'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { CancellationToken } from 'vs/base/common/cancellation'; import { isWeb } from 'vs/base/common/platform'; +import { UserDataSyncStoreClient } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; +import { getServiceMachineId } from 'vs/platform/serviceMachineId/common/serviceMachineId'; +import { generateUuid } from 'vs/base/common/uuid'; +import { IHeaders } from 'vs/base/parts/request/common/request'; +import { ILogService } from 'vs/platform/log/common/log'; const argvStoragePrefx = 'globalState.argv.'; const argvProperties: string[] = ['locale']; @@ -41,6 +46,18 @@ export interface IGlobalStateResourcePreview extends IResourcePreview { readonly storageKeys: StorageKeys; } +function formatAndStringify(globalState: IGlobalState): string { + const storageKeys = globalState.storage ? Object.keys(globalState.storage).sort() : []; + const storage: IStringDictionary = {}; + storageKeys.forEach(key => storage[key] = globalState.storage[key]); + globalState.storage = storage; + const content = JSON.stringify(globalState); + const edits = format(content, undefined, {}); + return applyEdits(content, edits); +} + +const GLOBAL_STATE_DATA_VERSION = 1; + /** * Synchronises global state that includes * - Global storage with user scope @@ -53,7 +70,7 @@ export interface IGlobalStateResourcePreview extends IResourcePreview { export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUserDataSynchroniser { private static readonly GLOBAL_STATE_DATA_URI = URI.from({ scheme: USER_DATA_SYNC_SCHEME, authority: 'globalState', path: `/globalState.json` }); - protected readonly version: number = 1; + protected readonly version: number = GLOBAL_STATE_DATA_VERSION; private readonly previewResource: URI = this.extUri.joinPath(this.syncPreviewFolder, 'globalState.json'); private readonly localResource: URI = this.previewResource.with({ scheme: USER_DATA_SYNC_SCHEME, authority: 'local' }); private readonly remoteResource: URI = this.previewResource.with({ scheme: USER_DATA_SYNC_SCHEME, authority: 'remote' }); @@ -108,10 +125,10 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs return [{ localResource: this.localResource, - localContent: this.format(localGloablState), + localContent: formatAndStringify(localGloablState), localUserData: localGloablState, remoteResource: this.remoteResource, - remoteContent: remoteGlobalState ? this.format(remoteGlobalState) : null, + remoteContent: remoteGlobalState ? formatAndStringify(remoteGlobalState) : null, previewResource: this.previewResource, previewResult, localChange: previewResult.localChange, @@ -216,7 +233,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs async resolveContent(uri: URI): Promise { if (this.extUri.isEqual(uri, GlobalStateSynchroniser.GLOBAL_STATE_DATA_URI)) { const localGlobalState = await this.getLocalGlobalState(); - return this.format(localGlobalState); + return formatAndStringify(localGlobalState); } if (this.extUri.isEqual(this.remoteResource, uri) || this.extUri.isEqual(this.localResource, uri) || this.extUri.isEqual(this.acceptedResource, uri)) { @@ -234,7 +251,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs if (syncData) { switch (this.extUri.basename(uri)) { case 'globalState.json': - return this.format(JSON.parse(syncData.content)); + return formatAndStringify(JSON.parse(syncData.content)); } } } @@ -242,16 +259,6 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs return null; } - private format(globalState: IGlobalState): string { - const storageKeys = globalState.storage ? Object.keys(globalState.storage).sort() : []; - const storage: IStringDictionary = {}; - storageKeys.forEach(key => storage[key] = globalState.storage[key]); - globalState.storage = storage; - const content = JSON.stringify(globalState); - const edits = format(content, undefined, {}); - return applyEdits(content, edits); - } - async hasLocalData(): Promise { try { const { storage } = await this.getLocalGlobalState(); @@ -410,3 +417,62 @@ export class GlobalStateInitializer extends AbstractInitializer { } +export class UserDataSyncStoreTypeSynchronizer { + + constructor( + private readonly userDataSyncStoreClient: UserDataSyncStoreClient, + @IStorageService private readonly storageService: IStorageService, + @IEnvironmentService private readonly environmentService: IEnvironmentService, + @IFileService private readonly fileService: IFileService, + @ILogService private readonly logService: ILogService, + ) { + } + + getSyncStoreType(userData: IUserData): UserDataSyncStoreType | undefined { + const remoteGlobalState = this.parseGlobalState(userData); + return remoteGlobalState?.storage[SYNC_SERVICE_URL_TYPE]?.value as UserDataSyncStoreType; + } + + async sync(userDataSyncStoreType: UserDataSyncStoreType): Promise { + const syncHeaders = createSyncHeaders(generateUuid()); + try { + return await this.doSync(userDataSyncStoreType, syncHeaders); + } catch (e) { + if (e instanceof UserDataSyncError) { + switch (e.code) { + case UserDataSyncErrorCode.PreconditionFailed: + this.logService.info(`Failed to synchronize UserDataSyncStoreType as there is a new remote version available. Synchronizing again...`); + return this.doSync(userDataSyncStoreType, syncHeaders); + } + } + throw e; + } + } + + private async doSync(userDataSyncStoreType: UserDataSyncStoreType, syncHeaders: IHeaders): Promise { + // Read the global state from remote + const globalStateUserData = await this.userDataSyncStoreClient.read(SyncResource.GlobalState, null, syncHeaders); + const remoteGlobalState = this.parseGlobalState(globalStateUserData) || { storage: {} }; + + // Update the sync store type + remoteGlobalState.storage[SYNC_SERVICE_URL_TYPE] = { value: userDataSyncStoreType, version: GLOBAL_STATE_DATA_VERSION }; + + // Write the global state to remote + const machineId = await getServiceMachineId(this.environmentService, this.fileService, this.storageService); + const syncDataToUpdate: ISyncData = { version: GLOBAL_STATE_DATA_VERSION, machineId, content: formatAndStringify(remoteGlobalState) }; + await this.userDataSyncStoreClient.write(SyncResource.GlobalState, JSON.stringify(syncDataToUpdate), globalStateUserData.ref, syncHeaders); + } + + private parseGlobalState({ content }: IUserData): IGlobalState | null { + if (!content) { + return null; + } + const syncData = JSON.parse(content); + if (isSyncData(syncData)) { + return syncData ? JSON.parse(syncData.content) : null; + } + throw new Error('Invalid remote data'); + } + +} + diff --git a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts index 876f55d0054..0d258c8e48c 100644 --- a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts @@ -185,6 +185,7 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto this._register(userDataSyncStoreService.onDidChangeDonotMakeRequestsUntil(() => this.updateAutoSync())); this._register(Event.debounce(userDataSyncService.onDidChangeLocal, (last, source) => last ? [...last, source] : [source], 1000)(sources => this.triggerSync(sources, false, false))); this._register(Event.filter(this.userDataSyncResourceEnablementService.onDidChangeResourceEnablement, ([, enabled]) => enabled)(() => this.triggerSync(['resourceEnablement'], false, false))); + this._register(this.userDataSyncStoreManagementService.onDidChangeUserDataSyncStore(() => this.triggerSync(['userDataSyncStoreChanged'], false, false))); } } @@ -345,7 +346,8 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto this.logService.info('Auto Sync: Turned off sync because default sync service is changed.'); } - // Service has changed by the user. So turn off and turn on sync silently + // Service has changed by the user. So turn off and turn on sync. + // Show a prompt to the user about service change. else { await this.turnOff(false, true /* force soft turnoff on error */, true /* do not disable machine */); await this.turnOn(); diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index afabfc02f64..d34583109a8 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -108,6 +108,7 @@ export type IAuthenticationProvider = { id: string, scopes: string[] }; export interface IUserDataSyncStore { readonly url: URI; + readonly type: UserDataSyncStoreType; readonly defaultUrl: URI; readonly stableUrl: URI; readonly insidersUrl: URI; @@ -149,7 +150,6 @@ export interface IUserDataSyncStoreManagementService { readonly _serviceBrand: undefined; readonly onDidChangeUserDataSyncStore: Event; readonly userDataSyncStore: IUserDataSyncStore | undefined; - set(type: UserDataSyncStoreType): void; switch(type: UserDataSyncStoreType): Promise; getPreviousUserDataSyncStore(): Promise; } @@ -193,6 +193,12 @@ export interface IUserDataSyncBackupStoreService { export const HEADER_OPERATION_ID = 'x-operation-id'; export const HEADER_EXECUTION_ID = 'X-Execution-Id'; +export function createSyncHeaders(executionId: string): IHeaders { + const headers: IHeaders = {}; + headers[HEADER_EXECUTION_ID] = executionId; + return headers; +} + //#endregion // #region User Data Sync Error diff --git a/src/vs/platform/userDataSync/common/userDataSyncIpc.ts b/src/vs/platform/userDataSync/common/userDataSyncIpc.ts index 21f82c43a6d..fc9acf98945 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncIpc.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncIpc.ts @@ -157,6 +157,7 @@ export class UserDataSyncStoreManagementServiceChannelClient extends Disposable private revive(userDataSyncStore: IUserDataSyncStore): IUserDataSyncStore { return { url: URI.revive(userDataSyncStore.url), + type: userDataSyncStore.type, defaultUrl: URI.revive(userDataSyncStore.defaultUrl), insidersUrl: URI.revive(userDataSyncStore.insidersUrl), stableUrl: URI.revive(userDataSyncStore.stableUrl), diff --git a/src/vs/platform/userDataSync/common/userDataSyncService.ts b/src/vs/platform/userDataSync/common/userDataSyncService.ts index cf0d022f8ca..b059b81ee40 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncService.ts @@ -5,7 +5,7 @@ import { IUserDataSyncService, SyncStatus, IUserDataSyncStoreService, SyncResource, IUserDataSyncLogService, IUserDataSynchroniser, UserDataSyncErrorCode, - UserDataSyncError, ISyncResourceHandle, IUserDataManifest, ISyncTask, IResourcePreview, IManualSyncTask, ISyncResourcePreview, HEADER_EXECUTION_ID, MergeState, Change, IUserDataSyncStoreManagementService, UserDataSyncStoreError + UserDataSyncError, ISyncResourceHandle, IUserDataManifest, ISyncTask, IResourcePreview, IManualSyncTask, ISyncResourcePreview, MergeState, Change, IUserDataSyncStoreManagementService, UserDataSyncStoreError, createSyncHeaders } from 'vs/platform/userDataSync/common/userDataSync'; import { Disposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -37,12 +37,6 @@ type SyncErrorClassification = { const LAST_SYNC_TIME_KEY = 'sync.lastSyncTime'; -function createSyncHeaders(executionId: string): IHeaders { - const headers: IHeaders = {}; - headers[HEADER_EXECUTION_ID] = executionId; - return headers; -} - export class UserDataSyncService extends Disposable implements IUserDataSyncService { _serviceBrand: any; diff --git a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts index e9454fce235..c12dedbad75 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts @@ -30,7 +30,7 @@ const MACHINE_SESSION_ID_KEY = 'sync.machine-session-id'; const REQUEST_SESSION_LIMIT = 100; const REQUEST_SESSION_INTERVAL = 1000 * 60 * 5; /* 5 minutes */ -type UserDataSyncStore = IUserDataSyncStore & { defaultType: UserDataSyncStoreType; type: UserDataSyncStoreType }; +type UserDataSyncStore = IUserDataSyncStore & { defaultType: UserDataSyncStoreType; }; export abstract class AbstractUserDataSyncStoreManagementService extends Disposable implements IUserDataSyncStoreManagementService { @@ -41,10 +41,10 @@ export abstract class AbstractUserDataSyncStoreManagementService extends Disposa private _userDataSyncStore: UserDataSyncStore | undefined; get userDataSyncStore(): UserDataSyncStore | undefined { return this._userDataSyncStore; } - private get userDataSyncStoreType(): UserDataSyncStoreType | undefined { + protected get userDataSyncStoreType(): UserDataSyncStoreType | undefined { return this.storageService.get(SYNC_SERVICE_URL_TYPE, StorageScope.GLOBAL) as UserDataSyncStoreType; } - private set userDataSyncStoreType(type: UserDataSyncStoreType | undefined) { + protected set userDataSyncStoreType(type: UserDataSyncStoreType | undefined) { this.storageService.store(SYNC_SERVICE_URL_TYPE, type, StorageScope.GLOBAL, isWeb ? StorageTarget.USER /* sync in web */ : StorageTarget.MACHINE); } @@ -55,6 +55,7 @@ export abstract class AbstractUserDataSyncStoreManagementService extends Disposa ) { super(); this.updateUserDataSyncStore(); + this._register(Event.filter(storageService.onDidChangeValue, e => e.key === SYNC_SERVICE_URL_TYPE && e.scope === StorageScope.GLOBAL && this.userDataSyncStoreType !== this.userDataSyncStore?.type)(() => this.updateUserDataSyncStore())); } protected updateUserDataSyncStore(): void { @@ -96,12 +97,6 @@ export abstract class AbstractUserDataSyncStoreManagementService extends Disposa return undefined; } - set(type: UserDataSyncStoreType) { - if (this.userDataSyncStore) { - this.userDataSyncStoreType = type; - } - } - abstract switch(type: UserDataSyncStoreType): Promise; abstract getPreviousUserDataSyncStore(): Promise; @@ -132,8 +127,8 @@ export class UserDataSyncStoreManagementService extends AbstractUserDataSyncStor } async switch(type: UserDataSyncStoreType): Promise { - if (this.userDataSyncStore?.canSwitch && type !== this.userDataSyncStore.type) { - this.set(type); + if (type !== this.userDataSyncStoreType) { + this.userDataSyncStoreType = type; this.updateUserDataSyncStore(); } } diff --git a/src/vs/platform/userDataSync/test/common/userDataSyncStoreService.test.ts b/src/vs/platform/userDataSync/test/common/userDataSyncStoreService.test.ts index 4550c939bb5..345fe859c44 100644 --- a/src/vs/platform/userDataSync/test/common/userDataSyncStoreService.test.ts +++ b/src/vs/platform/userDataSync/test/common/userDataSyncStoreService.test.ts @@ -51,6 +51,7 @@ suite('UserDataSyncStoreManagementService', () => { const expected: IUserDataSyncStore = { url: URI.parse('http://configureHost:3000'), + type: 'stable', defaultUrl: URI.parse('http://configureHost:3000'), stableUrl: URI.parse('http://configureHost:3000'), insidersUrl: URI.parse('http://configureHost:3000'), diff --git a/src/vs/workbench/contrib/update/browser/update.ts b/src/vs/workbench/contrib/update/browser/update.ts index 1ac14573954..2315cdb25b0 100644 --- a/src/vs/workbench/contrib/update/browser/update.ts +++ b/src/vs/workbench/contrib/update/browser/update.ts @@ -27,8 +27,11 @@ import { ShowCurrentReleaseNotesActionId, CheckForVSCodeUpdateActionId } from 'v import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IProductService } from 'vs/platform/product/common/productService'; import product from 'vs/platform/product/common/product'; -import { IUserDataAutoSyncEnablementService, IUserDataSyncStoreManagementService, UserDataSyncStoreType } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataAutoSyncEnablementService, IUserDataSyncService, IUserDataSyncStoreManagementService, SyncStatus, UserDataSyncStoreType } from 'vs/platform/userDataSync/common/userDataSync'; import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; +import { Promises } from 'vs/base/common/async'; +import { IUserDataSyncWorkbenchService } from 'vs/workbench/services/userDataSync/common/userDataSync'; +import { Event } from 'vs/base/common/event'; export const CONTEXT_UPDATE_STATE = new RawContextKey('updateState', StateType.Idle); @@ -513,7 +516,7 @@ export class SwitchProductQualityContribution extends Disposable implements IWor constructor( @IProductService private readonly productService: IProductService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, + @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService ) { super(); @@ -546,15 +549,23 @@ export class SwitchProductQualityContribution extends Disposable implements IWor const userDataAutoSyncEnablementService = accessor.get(IUserDataAutoSyncEnablementService); const userDataSyncStoreManagementService = accessor.get(IUserDataSyncStoreManagementService); const storageService = accessor.get(IStorageService); + const userDataSyncWorkbenchService = accessor.get(IUserDataSyncWorkbenchService); + const userDataSyncService = accessor.get(IUserDataSyncService); const selectSettingsSyncServiceDialogShownKey = 'switchQuality.selectSettingsSyncServiceDialogShown'; + const userDataSyncStore = userDataSyncStoreManagementService.userDataSyncStore; let userDataSyncStoreType: UserDataSyncStoreType | undefined; - if (isSwitchingToInsiders && userDataAutoSyncEnablementService.isEnabled() + if (userDataSyncStore && isSwitchingToInsiders && userDataAutoSyncEnablementService.isEnabled() && !storageService.getBoolean(selectSettingsSyncServiceDialogShownKey, StorageScope.GLOBAL, false)) { userDataSyncStoreType = await this.selectSettingsSyncService(dialogService); if (!userDataSyncStoreType) { return; } + storageService.store(selectSettingsSyncServiceDialogShownKey, true, StorageScope.GLOBAL, StorageTarget.USER); + if (userDataSyncStoreType === 'stable') { + // Update the stable service type in the current window, so that it uses stable service after switched to insiders version (after reload). + await userDataSyncStoreManagementService.switch(userDataSyncStoreType); + } } const res = await dialogService.confirm({ @@ -567,12 +578,26 @@ export class SwitchProductQualityContribution extends Disposable implements IWor }); if (res.confirmed) { - if (userDataSyncStoreType !== undefined) { - userDataSyncStoreManagementService.set(userDataSyncStoreType); - storageService.store(selectSettingsSyncServiceDialogShownKey, true, StorageScope.GLOBAL, StorageTarget.USER); - await storageService.flush(); + const promises: Promise[] = []; + + // If sync is happening wait until it is finished before reload + if (userDataSyncService.status === SyncStatus.Syncing) { + promises.push(Event.toPromise(Event.filter(userDataSyncService.onDidChangeStatus, status => status !== SyncStatus.Syncing))); } + + // Synchronise the store type option in insiders service, so that other clients using insiders service are also updated. + if (isSwitchingToInsiders) { + promises.push(userDataSyncWorkbenchService.synchroniseUserDataSyncStoreType()); + } + + await Promises.settled(promises); + productQualityChangeHandler(newQuality); + } else { + // Reset + if (userDataSyncStoreType) { + storageService.remove(selectSettingsSyncServiceDialogShownKey, StorageScope.GLOBAL); + } } } @@ -586,7 +611,7 @@ export class SwitchProductQualityContribution extends Disposable implements IWor nls.localize('cancel', "Cancel"), ], { - detail: nls.localize('selectSyncService.detail', "Insiders version of VSCode will synchronize your settings, keybindings, extensions, snippets and UI State using separete insiders settings sync service by default."), + detail: nls.localize('selectSyncService.detail', "Insiders version of VSCode will synchronize your settings, keybindings, extensions, snippets and UI State using separate insiders settings sync service by default."), cancelId: 2 } ); diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 4d0b65c016b..1d9a753a1bb 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -111,7 +111,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo @IOutputService private readonly outputService: IOutputService, @IUserDataSyncAccountService readonly authTokenService: IUserDataSyncAccountService, @IUserDataAutoSyncEnablementService private readonly userDataAutoSyncEnablementService: IUserDataAutoSyncEnablementService, - @IUserDataAutoSyncService private readonly userDataAutoSyncService: IUserDataAutoSyncService, + @IUserDataAutoSyncService userDataAutoSyncService: IUserDataAutoSyncService, @ITextModelService textModelResolverService: ITextModelService, @IPreferencesService private readonly preferencesService: IPreferencesService, @ITelemetryService private readonly telemetryService: ITelemetryService, @@ -323,13 +323,31 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } }); return; + + case UserDataSyncErrorCode.ServiceChanged: + this.notificationService.notify({ + severity: Severity.Info, + message: this.userDataSyncStoreManagementService.userDataSyncStore?.type === 'insiders' ? + localize('service switched to insiders', "Settings Sync has been switched to insiders service") : + localize('service switched to stable', "Settings Sync has been switched to stable service"), + }); + + return; + case UserDataSyncErrorCode.DefaultServiceChanged: - // Check if Settings Sync got turned off because default service has changed. - // Then ask user to turn on sync again. - if (!this.userDataAutoSyncEnablementService.isEnabled()) { + // Settings sync is using separate service + if (this.userDataAutoSyncEnablementService.isEnabled()) { this.notificationService.notify({ severity: Severity.Info, - message: localize('switched to insiders', "Settings sync was turned off because VSCode now uses a separate service. Please turn on sync again."), + message: localize('using separate service', "Settings sync now uses a separate service, more information is available in the [Settings Sync Documentation](https://aka.ms/vscode-settings-sync-help#_syncing-stable-versus-insiders)."), + }); + } + + // If settings sync got turned off then ask user to turn on sync again. + else { + this.notificationService.notify({ + severity: Severity.Info, + message: localize('service changed and turned off', "Settings sync was turned off because VSCode now uses a separate service. Please turn on sync again."), actions: { primary: [new Action('turn on sync', localize('turn on sync', "Turn on Settings Sync..."), undefined, true, () => this.turnOn())] } @@ -1035,7 +1053,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo }); } run(accessor: ServicesAccessor): Promise { - return that.userDataAutoSyncService.triggerSync([syncNowCommand.id], false, true); + return that.userDataSyncWorkbenchService.syncNow(); } })); } diff --git a/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts b/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts index e8234813c97..4a2f05f35f9 100644 --- a/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts +++ b/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts @@ -644,8 +644,6 @@ class SimpleUserDataSyncStoreManagementService implements IUserDataSyncStoreMana userDataSyncStore: IUserDataSyncStore | undefined = undefined; - set(type: UserDataSyncStoreType): void { } - async switch(type: UserDataSyncStoreType): Promise { } async getPreviousUserDataSyncStore(): Promise { return undefined; } diff --git a/src/vs/workbench/services/userData/browser/userDataInit.ts b/src/vs/workbench/services/userData/browser/userDataInit.ts index 380f47eafde..c001c65863c 100644 --- a/src/vs/workbench/services/userData/browser/userDataInit.ts +++ b/src/vs/workbench/services/userData/browser/userDataInit.ts @@ -5,7 +5,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ExtensionsInitializer } from 'vs/platform/userDataSync/common/extensionsSync'; -import { GlobalStateInitializer } from 'vs/platform/userDataSync/common/globalStateSync'; +import { GlobalStateInitializer, UserDataSyncStoreTypeSynchronizer } from 'vs/platform/userDataSync/common/globalStateSync'; import { KeybindingsInitializer } from 'vs/platform/userDataSync/common/keybindingsSync'; import { SettingsInitializer } from 'vs/platform/userDataSync/common/settingsSync'; import { SnippetsInitializer } from 'vs/platform/userDataSync/common/snippetsSync'; @@ -16,8 +16,8 @@ import { ILogService } from 'vs/platform/log/common/log'; import { UserDataSyncStoreClient } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; import { IProductService } from 'vs/platform/product/common/productService'; import { IRequestService } from 'vs/platform/request/common/request'; -import { ISyncExtension, IUserDataInitializer, IUserDataSyncLogService, IUserDataSyncStoreClient, IUserDataSyncStoreManagementService, SyncResource } from 'vs/platform/userDataSync/common/userDataSync'; -import { getCurrentAuthenticationSessionInfo } from 'vs/workbench/services/authentication/browser/authenticationService'; +import { ISyncExtension, IUserData, IUserDataInitializer, IUserDataSyncLogService, IUserDataSyncStoreClient, IUserDataSyncStoreManagementService, SyncResource } from 'vs/platform/userDataSync/common/userDataSync'; +import { AuthenticationSessionInfo, getCurrentAuthenticationSessionInfo } from 'vs/workbench/services/authentication/browser/authenticationService'; import { getSyncAreaLabel } from 'vs/workbench/services/userDataSync/common/userDataSync'; import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -30,6 +30,8 @@ import { IExtensionService, toExtensionDescription } from 'vs/workbench/services import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { mark } from 'vs/base/common/performance'; import { IIgnoredExtensionsManagementService } from 'vs/platform/userDataSync/common/ignoredExtensions'; +import { DisposableStore } from 'vs/base/common/lifecycle'; +import { isEqual } from 'vs/base/common/resources'; export const IUserDataInitializationService = createDecorator('IUserDataInitializationService'); export interface IUserDataInitializationService { @@ -47,6 +49,7 @@ export class UserDataInitializationService implements IUserDataInitializationSer private readonly initialized: SyncResource[] = []; private readonly initializationFinished = new Barrier(); + private globalStateUserData: IUserData | null = null; constructor( @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @@ -88,12 +91,6 @@ export class UserDataInitializationService implements IUserDataInitializationSer return; } - const userDataSyncStore = this.userDataSyncStoreManagementService.userDataSyncStore; - if (!userDataSyncStore) { - this.logService.trace(`Skipping initializing user data as sync service is not provided`); - return; - } - if (!this.environmentService.options?.credentialsProvider) { this.logService.trace(`Skipping initializing user data as credentials provider is not provided`); return; @@ -110,6 +107,15 @@ export class UserDataInitializationService implements IUserDataInitializationSer return; } + await this.initializeUserDataSyncStore(authenticationSession); + + const userDataSyncStore = this.userDataSyncStoreManagementService.userDataSyncStore; + if (!userDataSyncStore) { + this.logService.trace(`Skipping initializing user data as sync service is not provided`); + return; + } + + this.logService.info(`Using settings sync service ${userDataSyncStore.url.toString()} for initialization`); const userDataSyncStoreClient = new UserDataSyncStoreClient(userDataSyncStore.url, this.productService, this.requestService, this.logService, this.environmentService, this.fileService, this.storageService); userDataSyncStoreClient.setAuthToken(authenticationSession.accessToken, authenticationSession.providerId); return userDataSyncStoreClient; @@ -119,6 +125,37 @@ export class UserDataInitializationService implements IUserDataInitializationSer return this._userDataSyncStoreClientPromise; } + private async initializeUserDataSyncStore(authenticationSession: AuthenticationSessionInfo): Promise { + const userDataSyncStore = this.userDataSyncStoreManagementService.userDataSyncStore; + if (!userDataSyncStore?.canSwitch) { + return; + } + + const disposables = new DisposableStore(); + try { + const userDataSyncStoreClient = disposables.add(new UserDataSyncStoreClient(userDataSyncStore.url, this.productService, this.requestService, this.logService, this.environmentService, this.fileService, this.storageService)); + userDataSyncStoreClient.setAuthToken(authenticationSession.accessToken, authenticationSession.providerId); + + // Cache global state data for global state initialization + this.globalStateUserData = await userDataSyncStoreClient.read(SyncResource.GlobalState, null); + + if (this.globalStateUserData) { + const userDataSyncStoreType = new UserDataSyncStoreTypeSynchronizer(userDataSyncStoreClient, this.storageService, this.environmentService, this.fileService, this.logService).getSyncStoreType(this.globalStateUserData); + if (userDataSyncStoreType) { + await this.userDataSyncStoreManagementService.switch(userDataSyncStoreType); + + // Unset cached global state data if urls are changed + if (!isEqual(userDataSyncStore.url, this.userDataSyncStoreManagementService.userDataSyncStore?.url)) { + this.logService.info('Switched settings sync store'); + this.globalStateUserData = null; + } + } + } + } finally { + disposables.dispose(); + } + } + async whenInitializationFinished(): Promise { await this.initializationFinished.wait(); } @@ -158,7 +195,7 @@ export class UserDataInitializationService implements IUserDataInitializationSer this.initialized.push(syncResource); this.logService.trace(`Initializing ${getSyncAreaLabel(syncResource)}`); const initializer = this.createSyncResourceInitializer(syncResource, instantiationService); - const userData = await userDataSyncStoreClient.read(syncResource, null); + const userData = await userDataSyncStoreClient.read(syncResource, syncResource === SyncResource.GlobalState ? this.globalStateUserData : null); await initializer.initialize(userData); this.logService.info(`Initialized ${getSyncAreaLabel(syncResource)}`); } catch (error) { diff --git a/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts b/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts index 32228c4c3b0..cf80241f61a 100644 --- a/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts +++ b/src/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts @@ -31,6 +31,9 @@ import { URI } from 'vs/base/common/uri'; import { IViewsService, ViewContainerLocation, IViewDescriptorService } from 'vs/workbench/common/views'; import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { isWeb } from 'vs/base/common/platform'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { UserDataSyncStoreClient } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; +import { UserDataSyncStoreTypeSynchronizer } from 'vs/platform/userDataSync/common/globalStateSync'; type UserAccountClassification = { id: { classification: 'EndUserPseudonymizedInformation', purpose: 'BusinessInsight' }; @@ -109,6 +112,7 @@ export class UserDataSyncWorkbenchService extends Disposable implements IUserDat @IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService, @IUserDataSyncStoreManagementService private readonly userDataSyncStoreManagementService: IUserDataSyncStoreManagementService, @ILifecycleService private readonly lifecycleService: ILifecycleService, + @IInstantiationService private readonly instantiationService: IInstantiationService, ) { super(); this.syncEnablementContext = CONTEXT_SYNC_ENABLEMENT.bindTo(contextKeyService); @@ -280,6 +284,11 @@ export class UserDataSyncWorkbenchService extends Disposable implements IUserDat } await this.userDataAutoSyncService.turnOn(); + + if (this.userDataSyncStoreManagementService.userDataSyncStore?.canSwitch) { + await this.synchroniseUserDataSyncStoreType(); + } + this.notificationService.info(localize('sync turned on', "{0} is turned on", title)); } @@ -287,6 +296,25 @@ export class UserDataSyncWorkbenchService extends Disposable implements IUserDat return this.userDataAutoSyncService.turnOff(everywhere); } + async synchroniseUserDataSyncStoreType(): Promise { + if (!this.userDataSyncAccountService.account) { + throw new Error('Cannot update because you are signed out from settings sync. Please sign in and try again.'); + } + if (!isWeb || !this.userDataSyncStoreManagementService.userDataSyncStore) { + // Not supported + return; + } + + const userDataSyncStoreUrl = this.userDataSyncStoreManagementService.userDataSyncStore.type === 'insiders' ? this.userDataSyncStoreManagementService.userDataSyncStore.stableUrl : this.userDataSyncStoreManagementService.userDataSyncStore.insidersUrl; + const userDataSyncStoreClient = this.instantiationService.createInstance(UserDataSyncStoreClient, userDataSyncStoreUrl); + userDataSyncStoreClient.setAuthToken(this.userDataSyncAccountService.account.token, this.userDataSyncAccountService.account.authenticationProviderId); + await this.instantiationService.createInstance(UserDataSyncStoreTypeSynchronizer, userDataSyncStoreClient).sync(this.userDataSyncStoreManagementService.userDataSyncStore.type); + } + + syncNow(): Promise { + return this.userDataAutoSyncService.triggerSync(['Sync Now'], false, true); + } + private async onBeforeShutdown(manualSyncTask: IManualSyncTask): Promise { const result = await this.dialogService.confirm({ type: 'warning', diff --git a/src/vs/workbench/services/userDataSync/common/userDataSync.ts b/src/vs/workbench/services/userDataSync/common/userDataSync.ts index e46b1531589..c40f3fa8966 100644 --- a/src/vs/workbench/services/userDataSync/common/userDataSync.ts +++ b/src/vs/workbench/services/userDataSync/common/userDataSync.ts @@ -63,6 +63,9 @@ export interface IUserDataSyncWorkbenchService { resetSyncedData(): Promise; showSyncActivity(): Promise; + syncNow(): Promise; + + synchroniseUserDataSyncStoreType(): Promise; } export function getSyncAreaLabel(source: SyncResource): string { From 84a3428e924560da906800ae1a0227bcefcdd593 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 17 Feb 2021 19:12:21 +0100 Subject: [PATCH 268/325] update distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5438b01e552..b78d2019ffb 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.54.0", - "distro": "95f5b240383cb89b977a843ba09b27b72cfaf667", + "distro": "79c9c6cd047952944225cf04f5b19094d162e77f", "author": { "name": "Microsoft Corporation" }, From 4a2bb3569e7eeee3822be0e311b0afa64ef53f73 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 17 Feb 2021 10:25:12 -0800 Subject: [PATCH 269/325] Localize terminal context key descriptions Part of #116853 --- src/vs/workbench/contrib/terminal/common/terminal.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index e4ea96f5b74..4c891c2571e 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -18,11 +18,11 @@ export const TERMINAL_VIEW_ID = 'terminal'; export const KEYBINDING_CONTEXT_TERMINAL_IS_OPEN = new RawContextKey('terminalIsOpen', false, true); /** A context key that is set when the integrated terminal has focus. */ -export const KEYBINDING_CONTEXT_TERMINAL_FOCUS = new RawContextKey('terminalFocus', false, 'Whether the terminal is focused'); +export const KEYBINDING_CONTEXT_TERMINAL_FOCUS = new RawContextKey('terminalFocus', false, nls.localize('terminalFocusContextKey', "Whether the terminal is focused")); export const KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE_KEY = 'terminalShellType'; /** A context key that is set to the detected shell for the most recently active terminal, this is set to the last known value when no terminals exist. */ -export const KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE = new RawContextKey(KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE_KEY, undefined, { type: 'string', description: 'The shell type of the active terminal' }); +export const KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE = new RawContextKey(KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE_KEY, undefined, { type: 'string', description: nls.localize('terminalShellTypeContextKey', "The shell type of the active terminal") }); export const KEYBINDING_CONTEXT_TERMINAL_ALT_BUFFER_ACTIVE = new RawContextKey('terminalAltBufferActive', false, true); @@ -33,7 +33,7 @@ export const KEYBINDING_CONTEXT_TERMINAL_NOT_FOCUSED = KEYBINDING_CONTEXT_TERMIN export const KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS = new RawContextKey('terminalA11yTreeFocus', false, true); /** A keybinding context key that is set when the integrated terminal has text selected. */ -export const KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED = new RawContextKey('terminalTextSelected', false, 'Whether text is selected in the active terminal'); +export const KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED = new RawContextKey('terminalTextSelected', false, nls.localize('terminalTextSelectedContextKey', "Whether text is selected in the active terminal")); /** A keybinding context key that is set when the integrated terminal does not have text selected. */ export const KEYBINDING_CONTEXT_TERMINAL_TEXT_NOT_SELECTED = KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED.toNegated(); @@ -48,7 +48,7 @@ export const KEYBINDING_CONTEXT_TERMINAL_FIND_FOCUSED = new RawContextKey('terminalProcessSupported', false, 'Whether terminal processes can be launched'); +export const KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED = new RawContextKey('terminalProcessSupported', false, nls.localize('terminalProcessSupportedContextKey', "Whether terminal processes can be launched")); export const IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY = 'terminal.integrated.isWorkspaceShellAllowed'; export const NEVER_MEASURE_RENDER_TIME_STORAGE_KEY = 'terminal.integrated.neverMeasureRenderTime'; From 00b583d38d629e9ec3eb866d33116e7e9c68fb27 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru Date: Wed, 17 Feb 2021 19:39:55 +0100 Subject: [PATCH 270/325] =?UTF-8?q?=F0=9F=92=84=20class=20name=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../contrib/workspace/browser/workspace.contribution.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts index 04237e078bd..6240c337b3a 100644 --- a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts +++ b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts @@ -181,7 +181,7 @@ Registry.as(WorkbenchExtensions.Workbench).regi /** * Trusted Workspace GUI Editor */ -class WorkspaceTrustEditorInputInputFactory implements IEditorInputFactory { +class WorkspaceTrustEditorInputFactory implements IEditorInputFactory { canSerialize(editorInput: EditorInput): boolean { return true; @@ -197,7 +197,7 @@ class WorkspaceTrustEditorInputInputFactory implements IEditorInputFactory { } Registry.as(EditorInputExtensions.EditorInputFactories) - .registerEditorInputFactory(WorkspaceTrustEditorInput.ID, WorkspaceTrustEditorInputInputFactory); + .registerEditorInputFactory(WorkspaceTrustEditorInput.ID, WorkspaceTrustEditorInputFactory); Registry.as(EditorExtensions.Editors).registerEditor( EditorDescriptor.create( From 5a4f5c95fe3111a9fe8d5b4bbf1a98ab7694747f Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 17 Feb 2021 20:10:18 +0100 Subject: [PATCH 271/325] untitiled hint #114307 --- .../parts/editor/editor.contribution.ts | 4 + .../browser/parts/editor/untitledHint.ts | 150 ++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 src/vs/workbench/browser/parts/editor/untitledHint.ts diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index 78d51af076a..e7002d6b68c 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -57,6 +57,7 @@ import { IPathService } from 'vs/workbench/services/path/common/pathService'; import { FileAccess } from 'vs/base/common/network'; import { Codicon } from 'vs/base/common/codicons'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; +import { UntitledHintContribution } from 'vs/workbench/browser/parts/editor/untitledHint'; // Register String Editor Registry.as(EditorExtensions.Editors).registerEditor( @@ -276,6 +277,9 @@ Registry.as(WorkbenchExtensions.Workbench).regi // Register Editor Auto Save Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(EditorAutoSave, LifecyclePhase.Ready); +// Register Untitled Hint +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(UntitledHintContribution, LifecyclePhase.Ready); + // Register Status Actions const registry = Registry.as(ActionExtensions.WorkbenchActions); registry.registerWorkbenchAction(SyncActionDescriptor.from(ChangeModeAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_M) }), 'Change Language Mode'); diff --git a/src/vs/workbench/browser/parts/editor/untitledHint.ts b/src/vs/workbench/browser/parts/editor/untitledHint.ts new file mode 100644 index 00000000000..daa2d1ca59d --- /dev/null +++ b/src/vs/workbench/browser/parts/editor/untitledHint.ts @@ -0,0 +1,150 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as dom from 'vs/base/browser/dom'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition, isCodeEditor } from 'vs/editor/browser/editorBrowser'; +import { localize } from 'vs/nls'; +import { DEFAULT_FONT_FAMILY } from 'vs/workbench/browser/style'; +import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry'; +import { ChangeModeAction } from 'vs/workbench/browser/parts/editor/editorStatus'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; +import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; +const $ = dom.$; + +const UNTITLED_HINT_VISIBILITY_STORAGE_KEY = 'untitledHint.visible'; +export class UntitledHintContribution implements IWorkbenchContribution { + + private toDispose: IDisposable[]; + private untitledHintContentWidget: UntitledHintContentWidget | undefined; + + constructor( + @IEditorService private readonly editorService: IEditorService, + @ICommandService private readonly commandService: ICommandService, + @IStorageService private readonly storageService: IStorageService, + ) { + this.toDispose = []; + this.toDispose.push(this.editorService.onDidActiveEditorChange(() => this.onActiveEditorChange())); + this.onActiveEditorChange(); + } + + private onActiveEditorChange(): void { + const activeEditor = this.editorService.activeEditor; + this.untitledHintContentWidget?.dispose(); + + const activeCodeEditor = this.editorService.activeTextEditorControl; + const untitledHintVisible = this.storageService.getBoolean(UNTITLED_HINT_VISIBILITY_STORAGE_KEY, StorageScope.GLOBAL, true); + if (untitledHintVisible && activeEditor && activeEditor.isUntitled() && isCodeEditor(activeCodeEditor)) { + this.untitledHintContentWidget = new UntitledHintContentWidget(activeCodeEditor, this.commandService, this.storageService); + } + } + + dispose(): void { + dispose(this.toDispose); + this.untitledHintContentWidget?.dispose(); + } +} + +class UntitledHintContentWidget implements IContentWidget { + + private static readonly ID = 'editor.widget.untitledHint'; + + private domNode: HTMLElement | undefined; + private toDispose: IDisposable[]; + + constructor( + private readonly editor: ICodeEditor, + private readonly commandService: ICommandService, + private readonly storageService: IStorageService, + ) { + this.toDispose = []; + this.toDispose.push(editor.onDidChangeModelContent(() => this.onDidChangeModelContent())); + this.toDispose.push(editor.onDidChangeModelLanguage(() => this.onDidChangeModelContent())); + this.onDidChangeModelContent(); + } + + private onDidChangeModelContent(): void { + if (this.editor.getValue() === '' && this.editor.getModel()?.getModeId() === PLAINTEXT_MODE_ID) { + this.editor.addContentWidget(this); + } else { + this.editor.removeContentWidget(this); + } + } + + getId(): string { + return UntitledHintContentWidget.ID; + } + + + // Select a language to get started. Start typing to dismiss, or don't show this again. + getDomNode(): HTMLElement { + if (!this.domNode) { + this.domNode = $('.untitled-hint'); + this.domNode.style.width = 'max-content'; + const select = $('span'); + select.innerText = localize('select', "Select a "); + this.domNode.appendChild(select); + const language = $('span.language-mode.detected-link-active'); + language.innerText = localize('language', "language"); + this.domNode.appendChild(language); + const toGetStarted = $('span'); + toGetStarted.innerText = localize('toGetStarted', " to get started. Start typing to dismiss, or "); + this.domNode.appendChild(toGetStarted); + + const dontShow = $('span.detected-link-active'); + dontShow.innerText = localize('dontshow', "don't show"); + this.domNode.appendChild(dontShow); + + const thisAgain = $('span'); + thisAgain.innerText = localize('thisAgain', " this again."); + this.domNode.appendChild(thisAgain); + + this.toDispose.push(dom.addDisposableListener(language, 'click', async e => { + e.stopPropagation(); + await this.commandService.executeCommand(ChangeModeAction.ID); + this.editor.focus(); + })); + + this.toDispose.push(dom.addDisposableListener(dontShow, 'click', () => { + this.storageService.store(UNTITLED_HINT_VISIBILITY_STORAGE_KEY, false, StorageScope.GLOBAL, StorageTarget.USER); + this.dispose(); + this.editor.focus(); + })); + + this.toDispose.push(dom.addDisposableListener(this.domNode, 'click', () => { + this.editor.focus(); + })); + + this.domNode.style.fontFamily = DEFAULT_FONT_FAMILY; + this.domNode.style.fontStyle = 'italic'; + this.domNode.style.paddingLeft = '4px'; + } + + return this.domNode; + } + + getPosition(): IContentWidgetPosition | null { + return { + position: { lineNumber: 1, column: 1 }, + preference: [ContentWidgetPositionPreference.EXACT] + }; + } + + dispose(): void { + this.editor.removeContentWidget(this); + dispose(this.toDispose); + } +} + +registerThemingParticipant((theme, collector) => { + const inputPlaceholderForegroundColor = theme.getColor(inputPlaceholderForeground); + if (inputPlaceholderForegroundColor) { + collector.addRule(`.monaco-editor .contentWidgets .untitled-hint { color: ${inputPlaceholderForegroundColor}; }`); + } +}); From 4e19a9f16ab8dca0b027796bd84bf5375d778323 Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Tue, 16 Feb 2021 10:24:48 -0800 Subject: [PATCH 272/325] Update telemetry classification type for isEdu check --- extensions/github-authentication/src/githubServer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/github-authentication/src/githubServer.ts b/extensions/github-authentication/src/githubServer.ts index 13ec13b735b..6a0ecfa357f 100644 --- a/extensions/github-authentication/src/githubServer.ts +++ b/extensions/github-authentication/src/githubServer.ts @@ -229,7 +229,7 @@ export class GitHubServer { /* __GDPR__ "session" : { - "isEdu": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + "isEdu": { "classification": "NonIdentifiableDemographicInfo", "purpose": "FeatureInsight" } } */ this.telemetryReporter.sendTelemetryEvent('session', { From a5ff0dd6eeeb79c91e989c983002ee9a3c466d35 Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Wed, 17 Feb 2021 11:35:23 -0800 Subject: [PATCH 273/325] Return from getSession earlier when requesting session access --- src/vs/workbench/api/browser/mainThreadAuthentication.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/workbench/api/browser/mainThreadAuthentication.ts b/src/vs/workbench/api/browser/mainThreadAuthentication.ts index 64f7d14880f..114ac174f64 100644 --- a/src/vs/workbench/api/browser/mainThreadAuthentication.ts +++ b/src/vs/workbench/api/browser/mainThreadAuthentication.ts @@ -227,6 +227,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu } } else { this.authenticationService.requestSessionAccess(providerId, extensionId, extensionName, [session]); + return undefined; } } } else { @@ -234,6 +235,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu session = await this.selectSession(providerId, extensionId, extensionName, sessions, !!options.clearSessionPreference); } else { this.authenticationService.requestSessionAccess(providerId, extensionId, extensionName, sessions); + return undefined; } } } else { From 4f12bb8451fce31fbc2c25521dfa91bd00d9d081 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Wed, 17 Feb 2021 11:45:30 -0800 Subject: [PATCH 274/325] First cut of allowing extensions to contribute getting started content. Closes #116414. --- .../platform/extensions/common/extensions.ts | 10 ++ .../gettingStarted/browser/gettingStarted.ts | 10 +- .../common/gettingStartedContent.ts | 13 ++- .../common/gettingStartedRegistry.ts | 95 +++++++++++++++++++ .../common/gettingStartedService.ts | 68 ++++++++++++- 5 files changed, 189 insertions(+), 7 deletions(-) diff --git a/src/vs/platform/extensions/common/extensions.ts b/src/vs/platform/extensions/common/extensions.ts index 8f0a3b204c3..a3b24d7c4a7 100644 --- a/src/vs/platform/extensions/common/extensions.ts +++ b/src/vs/platform/extensions/common/extensions.ts @@ -113,6 +113,15 @@ export interface IAuthenticationContribution { readonly label: string; } +export interface IGettingStartedContent { + readonly id: string; + readonly title: string; + readonly description: string; + readonly button: { title: string } & ({ command?: never, link: string } | { command: string, link?: never }), + readonly media: { path: string | { hc: string, light: string, dark: string }, altText: string }, + readonly when?: string; +} + export interface IExtensionContributions { commands?: ICommand[]; configuration?: IConfiguration | IConfiguration[]; @@ -132,6 +141,7 @@ export interface IExtensionContributions { readonly customEditors?: readonly IWebviewEditor[]; readonly codeActions?: readonly ICodeActionContribution[]; authentication?: IAuthenticationContribution[]; + gettingStarted?: IGettingStartedContent[]; } export type ExtensionKind = 'ui' | 'workspace' | 'web'; diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts index f890c8f273e..45ea20fbcaf 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts @@ -104,7 +104,11 @@ export class GettingStartedPage extends EditorPane { this.gettingStartedCategories = this.gettingStartedService.getCategories(); this._register(this.dispatchListeners); - this._register(this.gettingStartedService.onDidAddTask(task => console.log('added new task', task, 'that isnt being rendered yet'))); + this._register(this.gettingStartedService.onDidAddTask(task => { + this.gettingStartedCategories = this.gettingStartedService.getCategories(); + this.buildCategoriesSlide(); + })); + this._register(this.gettingStartedService.onDidAddCategory(category => console.log('added new category', category, 'that isnt being rendered yet'))); this._register(this.gettingStartedService.onDidProgressTask(task => { const category = this.gettingStartedCategories.find(category => category.id === task.category); @@ -307,9 +311,7 @@ export class GettingStartedPage extends EditorPane { $('.category-description.description', { 'aria-label': category.description + ' ' + localize('pressEnterToSelect', "Press Enter to Select") }, category.description), $('.category-progress', { 'x-data-category-id': category.id, }, $('.message'), - $('.progress-bar-outer', { - 'role': 'progressbar' - }, + $('.progress-bar-outer', { 'role': 'progressbar' }, $('.progress-bar-inner')))) : $('.category-description-container', {}, diff --git a/src/vs/workbench/services/gettingStarted/common/gettingStartedContent.ts b/src/vs/workbench/services/gettingStarted/common/gettingStartedContent.ts index 64e10c2eb92..3e98f0e75c1 100644 --- a/src/vs/workbench/services/gettingStarted/common/gettingStartedContent.ts +++ b/src/vs/workbench/services/gettingStarted/common/gettingStartedContent.ts @@ -12,6 +12,7 @@ import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; const setupIcon = registerIcon('getting-started-setup', Codicon.heart, localize('getting-started-setup-icon', "Icon used for the setup category of getting started")); const beginnerIcon = registerIcon('getting-started-beginner', Codicon.lightbulb, localize('getting-started-beginner-icon', "Icon used for the beginner category of getting started")); const codespacesIcon = registerIcon('getting-started-codespaces', Codicon.github, localize('getting-started-codespaces-icon', "Icon used for the codespaces category of getting started")); +const extensionsIcon = registerIcon('getting-started-extensions', Codicon.extensions, localize('getting-started-extensions-icon', "Icon used for the extensions category of getting started")); type GettingStartedItem = { @@ -269,6 +270,16 @@ export const content: GettingStartedContent = [ } ] } - } + }, + { + id: 'ExtensionContrib', + title: localize('gettingStarted.extensionContrib.title', "Discover Your Extensions"), + icon: extensionsIcon, + description: localize('gettingStarted.extensionContrib.description', "Learn about features contributed by installed extensions."), + content: { + type: 'items', + items: [] + } + } ]; diff --git a/src/vs/workbench/services/gettingStarted/common/gettingStartedRegistry.ts b/src/vs/workbench/services/gettingStarted/common/gettingStartedRegistry.ts index c6f32091b3e..f77f204417e 100644 --- a/src/vs/workbench/services/gettingStarted/common/gettingStartedRegistry.ts +++ b/src/vs/workbench/services/gettingStarted/common/gettingStartedRegistry.ts @@ -7,9 +7,11 @@ import { Emitter, Event } from 'vs/base/common/event'; import { FileAccess } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; +import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { Registry } from 'vs/platform/registry/common/platform'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { content } from 'vs/workbench/services/gettingStarted/common/gettingStartedContent'; +import { localize } from 'vs/nls'; export const enum GettingStartedCategory { Beginner = 'Beginner', @@ -165,3 +167,96 @@ content.forEach(category => { Registry.add(GettingStartedRegistryID, registryImpl); export const GettingStartedRegistry: IGettingStartedRegistry = Registry.as(GettingStartedRegistryID); + +ExtensionsRegistry.registerExtensionPoint({ + extensionPoint: 'gettingStarted', + jsonSchema: { + doNotSuggest: true, + description: localize('gettingStarted', "Contribute items to help users in getting started with your extension. Rendering and progression through these items is managed by core. Experimental, requires proposedApi."), + type: 'array', + items: { + type: 'object', + required: ['id', 'title', 'description', 'button', 'media'], + properties: { + id: { + type: 'string', + description: localize('gettingStarted.id', "Unique identifier for this item."), + }, + title: { + type: 'string', + description: localize('gettingStarted.title', "Title of item.") + }, + description: { + type: 'string', + description: localize('gettingStarted.description', "Description of item.") + }, + button: { + description: localize('gettingStarted.button', "The item's button, which can either link to an external resource or run a command"), + oneOf: [ + { + type: 'object', + required: ['title', 'command'], + properties: { + title: { + type: 'string', + description: localize('gettingStarted.button.title', "Title of button.") + }, + command: { + type: 'string', + description: localize('gettingStarted.button.command', "Command to run when button is clicked. Running this command will mark the item completed.") + } + } + }, + { + type: 'object', + required: ['title', 'link'], + properties: { + title: { + type: 'string', + description: localize('gettingStarted.button.title', "Title of button.") + }, + link: { + type: 'string', + description: localize('gettingStarted.button.link', "Link to open when button is clicked. Opening this link will mark the item completed.") + } + } + } + ] + }, + media: { + type: 'object', + required: ['path', 'altText'], + description: localize('gettingStarted.media', "Image to show alongside this item."), + properties: { + path: { + description: localize('gettingStarted.media.path', "Either a single string path to an image to be used on all color themes, or separate paths for light, dark, and high contrast themes."), + + oneOf: [ + { + type: 'string', + }, + { + type: 'object', + required: ['hc', 'light', 'dark'], + properties: { + hc: { type: 'string' }, + light: { type: 'string' }, + dark: { type: 'string' }, + } + }, + ] + }, + altText: { + type: 'string', + description: localize('gettingStarted.media.altText', "Alternate text to display when the image cannot be loaded or in screen readers.") + } + } + }, + when: { + type: 'string', + description: localize('gettingStarted.when', "Context key expression to control the visibility of this getting started item.") + } + } + } + } +}); diff --git a/src/vs/workbench/services/gettingStarted/common/gettingStartedService.ts b/src/vs/workbench/services/gettingStarted/common/gettingStartedService.ts index b5784ee9ddb..d741ae8683a 100644 --- a/src/vs/workbench/services/gettingStarted/common/gettingStartedService.ts +++ b/src/vs/workbench/services/gettingStarted/common/gettingStartedService.ts @@ -11,9 +11,13 @@ import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storag import { Memento } from 'vs/workbench/common/memento'; import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { Disposable } from 'vs/base/common/lifecycle'; import { IUserDataAutoSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { URI } from 'vs/base/common/uri'; +import { joinPath } from 'vs/base/common/resources'; export const IGettingStartedService = createDecorator('gettingStartedService'); @@ -63,11 +67,14 @@ export class GettingStartedService extends Disposable implements IGettingStarted private commandListeners = new Map(); private eventListeners = new Map(); + private trackedExtensions = new Set(); + constructor( @IStorageService private readonly storageService: IStorageService, @ICommandService private readonly commandService: ICommandService, @IContextKeyService private readonly contextService: IContextKeyService, @IUserDataAutoSyncEnablementService readonly userDataAutoSyncEnablementService: IUserDataAutoSyncEnablementService, + @IExtensionService private readonly extensionService: IExtensionService, ) { super(); @@ -80,7 +87,20 @@ export class GettingStartedService extends Disposable implements IGettingStarted } }); - this._register(this.registry.onDidAddCategory(category => this._onDidAddCategory.fire(this.getCategoryProgress(category)))); + this.extensionService.getExtensions().then(extensions => { + extensions.forEach(extension => this.registerExtensionContributions(extension)); + }); + + this.extensionService.onDidChangeExtensions(() => { + this.extensionService.getExtensions().then(extensions => { + extensions.forEach(extension => this.registerExtensionContributions(extension)); + }); + }); + + this._register(this.registry.onDidAddCategory(category => + this._onDidAddCategory.fire(this.getCategoryProgress(category)) + )); + this._register(this.registry.onDidAddTask(task => { this.registerDoneListeners(task); this._onDidAddTask.fire(this.getTaskProgress(task)); @@ -93,6 +113,50 @@ export class GettingStartedService extends Disposable implements IGettingStarted })); } + private registerExtensionContributions(extension: IExtensionDescription) { + const convertPaths = (path: string | { hc: string, dark: string, light: string }): { hc: URI, dark: URI, light: URI } => { + const convertPath = (path: string) => path.startsWith('https://') + ? URI.parse(path, true) + : joinPath(extension.extensionLocation, path); + + if (typeof path === 'string') { + const converted = convertPath(path); + return { hc: converted, dark: converted, light: converted }; + } else { + return { + hc: convertPath(path.hc), + light: convertPath(path.light), + dark: convertPath(path.dark) + }; + } + }; + + if (!this.trackedExtensions.has(ExtensionIdentifier.toKey(extension.identifier))) { + this.trackedExtensions.add(ExtensionIdentifier.toKey(extension.identifier)); + + if (extension.contributes?.gettingStarted?.length) { + if (!extension.enableProposedApi) { + console.warn('Extension', extension.identifier.value, 'contributes getting started content but has not enabled proposedApi. The contributed content will be disregarded.'); + return; + } + + extension.contributes?.gettingStarted.forEach((content, index) => { + this.registry.registerTask({ + button: content.button, + description: content.description, + media: { type: 'image', altText: content.media.altText, path: convertPaths(content.media.path) }, + doneOn: content.button.command ? { commandExecuted: content.button.command } : { eventFired: `linkOpened:${content.button.link}` }, + id: content.id, + title: content.title, + when: ContextKeyExpr.deserialize(content.when) ?? ContextKeyExpr.true(), + category: 'ExtensionContrib', + order: index, + }); + }); + } + } + } + private registerDoneListeners(task: IGettingStartedTask) { if (task.doneOn.commandExecuted) { const existing = this.commandListeners.get(task.doneOn.commandExecuted); From 8cec47ff4a3afdb27c8322a11a885bfaae9693d3 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Wed, 17 Feb 2021 12:00:33 -0800 Subject: [PATCH 275/325] Update Codicons --- .../browser/ui/codicons/codicon/codicon.ttf | Bin 64268 -> 64964 bytes src/vs/base/common/codicons.ts | 3 +++ 2 files changed, 3 insertions(+) diff --git a/src/vs/base/browser/ui/codicons/codicon/codicon.ttf b/src/vs/base/browser/ui/codicons/codicon/codicon.ttf index 01abb46b868b7211758d3e2b92189072fc12ff08..b1a42c0999c1083261e57c68b26650eb1e0fe03a 100644 GIT binary patch delta 4758 zcmbW4dsI}{y~lsQIl~Mv!!W}zGd$is)O=Ts!;zTrkcugME2;Wscq6JDgj;wh*>v2F+4b~ ze{?56`ZEBElg0xm-Jn$5q;qu(*HJ}wNA^Zuiu^=gA-@p5 zU+o+IBm5uif#0APeug?YiAk^s+fhIb#=``--~x=mK{yT`^gtizunq2o4R94+fz$9J zR>C*oes~D|m{~+!AweQI);7%FT+paEW8eH!Y|-0_$6F~ zx8WUl7k))A|1$gz-h(9VHuWV04s12F2*XXMiC{f!Fp`K zMr^_sY{g}`0`I^M?8Gj-6T5LG_P}@HD10CO8|q;xv_U&`Koh#*4(NjAAVDgm!7Ply zB>X!rrT3l)&F~bw3ZGyJoQH2<3@YIqn&1uaUjh-AgO7|g4*TI*I0L_h4EQ;`26>PV z0W8I4tixJd0uRDX_!M5E&Q{F~#w$<{TGspeDz;`82yf9ioBs$98Rk$ILWB&>pw5KI z2nT*cx}HNF43P~S_!;Ra2X*0hHI`~JUSx~|i%7>g*iO2Mg97Ph4r)jzI2a%HYMpo? z+^wxdPk29-+rlTb&IF28grdTLSHka6ePuX4p(Ny|x_{x2Z6NY>4s0Z))G)A^l(mFK z*-ZMc9Lyoz%RwjUzj4q)x{rgoqz`kjh;%;(^GL%0Dz-vL_+)}5A%m(8aLA{Z627A% zpMp$BGRUzY=X1!rAQy1R#UK}Q$j>0VIpl1R>5dHYILOor2Du&N5)SzuWDkcD0CFjZ zvH&vmQHZT579jgL6cCWhI209->Gd%vG$5CAC_W$uI20t1D>xJ>kf}Qv6fTe#b0}sY zS8^zDAd|Hi6ul70H2g6rg&>O@$|J}Uhmr|$4TmxcaxI6_3i1*T3+DV5vm_Oje04VmCDJV%tO-%!D;#8|nc^Tb$~_!pM)@iSnNPNIka=Sp2bnkS ze2s&5knZ3h^FWZOr4>^D%R4#9Jis1`K<0s69AqB2kAutu_j9l({G*fy&>e0_eE^q+ zUrwzIy-Ir?0Qm_HO%@>k2M4}E`XmQqNdJ>VQwhk2IB<^izc@6#fczAP zCK`~x!+}erPXmOf(+s#gd?2l{^bFNJ!=c#+daX|n9F9I~8GQKooPo=kP8u1~!`^-P*OZF^cIy(N8j`lXEijH8*5 z*_3%a^MX}p^;l0@FNJI>Tb^yF?K#^A_ECq~ahKzGR!!Dh&h^{b zbjcGXr#zFMy`JNqtED}qJ4)a3>b&FLZ+TC8ulO>2`+P^rRAr&^vK?hV@+oLcb_^QP-kM@xe-{?5TXS%3bxXs$*4Gs=d`)svoL8S$#=d zFCLLZ=}?WXW=G94wb`}nYWLP&U7}l(vE;+L@w!LqGwLVnBTIXh9&6AwENR%;aH(-w zAb9=l;%fT?e|(-x+^rcXvv6efRm5 zNh|lPJhAe6&$gZuz0ljx`%v$NK6hVt-&1{OSHY@`RXbO`+y6-aoBfNf^xs^qU2R>x zd-baW`hos|Lu*pjEL-#B+Jd!_!K%Tj!RLljhSm+87c{mA|q zxAk$G=AbYJIp79ANa1gb74bpr)G&#fXh#6t8n4}Rs3Sab_Xp82E;bmg6R#A}_ zeX#5gt*5a1^32!8j|ueoq5f7$sft$XvQ_;e~E?jCbtqB2qE&n_&sSEguFwFY}4#w8@iTCK5(32~TcH)zu| zDV6pjx3gTQS8A+!4W^rDU#vn9RLWR&LZU%qbs#F6sXg}QrnN(7J3ER!p5l(qvqNi} znrWhnpHYpi5<(iFMHmx~KpYsr1exHV-@rxGd5fSLXe=@MOilygGN9At5BMx5m(TBv zxvebRR=%yiP+{^JoF?Bua9|*4!vjH^Eoci$6238Kv(4FNgTaeITm6^oq#!NA5otb2 zv>&kVKF z=Rqf|gjKMHTH^FmJN}kTbown+8z2PQXL0%~6(*;T7ulxIF=+Vvznrl0*#_C24Mx z&;M9GT~au*u$!&u{GcS>l%)BylBDp?pH+CNE+_`^S(?PD(X1VR-|Kcg{vt=0X&1BKY|55-P#lqimI==!3X*{;W7)vki!I5)(-%lA>DLdtI9UDPE7BxhdMBEjDR3 zDA}WDY~swRcQ?jk?@Yn_M-?hXkD^!6H}j_Kj?)`9PfU#rO-zgxO^s}t93MRP(Hoc% gx8yd#)zqYBC$YxT#1LHj8*kIJr~h=$`ONpu zojY@9?*0DmZ|3-S!qKmVd(6I{0^leBv@cuTGyL7Kpa(!&2B3AV7`m&!dA;r!fYAmp zd1hdFPhZ@<7ev(d0#P_X71H;`B~+duQU+G9-%uc<65u5OamUcwWj)uny?h2BZWDmu z>D4_Oh6T652|6D`jS|=NtX`hGzb!pnRg=PTcQ~th*~sb2BxAB_Fybp>ET5n1_?;%8N%qPFq-@tX4hVNho zZa@fbq7X$WMhS*tI4V$yDvU%m>M$Dh7=v*bj|phPBuqgIreUrR^U#h3=)gjBVlkFr zDVAY5R$?{Q;4GYtbvOqb(1T6bjPtMs=VL3j!EfLxcp45t4a|aOmEOg{ti=j+p&NDu)`TlDjCUGs*zVshH_!PBAh?V{lL^5-22Cpjmos>82m2W` z)ev040P=BgfPr%VRk^-Af{q3mP)s_+z`3NW8N7LeYZyqT4z6XO)L)}8;|Kl$MJZsG7tnQYI$HK=}rb_lJajtpoa8k3`{1a z2(t8=GCEde7GwFQ{%pl#%z*JH{fP~+n(SJs%SH@D+gAB9=rj$=g$d6ji{LGAO=) zD`QZk`G6~@1A>AMI2VJ$4>&i20ui_h28ASWl?)0_;HnrDrodG*C}4rBVNmD-H;X|* z3|uXP!Wp>PJU;698!FT>D8_-C!=PvfuAV`04_pI-Rsi5U3|b3-Yh=)>02~>Z2X2x! zGf+r6kAWi676yt*ee-EYpoFxQfnlU=3=Ai2XP|;~0Rxq!9Sl^FE@WUNX(t2Kq>C7+ zBkf{fH0ff75A{^&X7I^{Tf)FN(xnWHC+%Ti0%=3C1^-h9Ih* z19|hUV_-SWKX*F=d1I|-AaABS7+6F4BL?zjx|4ytfi^IZ_s?AnLn^^hrCfXGmtk5|4;<-M%ltZ-X~ib$opi3fo=YGW42+szaw@VR{77zmipeH zGmkLfThd1vlo5b?j6t~pxL-2h9@6~`6p;RkL74-%#~JVz=@SgfCcqtFP+kG1|=Zi0t`6qPmIfPXVcO146G&n0|P5a zk226jI?kYk1>6J!c2WP&#QA*Lk@rWQioB*)sEz7ewM*Tu?pKdSX``~E9*;Vzk!dP4 zotizGG0kbsC)#AKN4r6LRC`9(uX|WG8EuKKi(VJ~Q1prD%X*c*R=-idU;lQDASO5F zvDl2*zSu3XCkz>e4Tj5cb#Xi5F2r}nkHv=)Y7-78oHHtn*~SUu1)oV|vY0lRj+nkk z>`&4r4I~{-b|s%R_oYOpw5BRj4_JmQA#07b!+OwqEzOX&H0@-%BHfifntm-KEn`c@ z`OMtR&6$U7;kHv*f~@sfpJZFIcV?f;{yL{GXG_jwxy`vlx%cOu$}7t2%6mTVO1>w5 zL;fTAlle3DVf)?o&kB6e1ziRE3obc~j#kHZ$B9B!p{sDSQ{n6@8Yntgbg8(tct`Qo zlGc)^N;68glwK~KDa$Y0R5np|u3T1bD}SbZ%C*yV#oggP;hwHoQ}J}g*~-Goj>`V3 zlBy$BA6NHRAFU~<*Wu7M*ZKCMor_K`I=|>j7j!wIx;Ayav{Q*ua=*$|B#WglJVz?({LQXx znIJ24FN#B6|1MXy5)D`s+8Daw`8}#$3cTvNo*{iv_#$Xwr+;^GOp`g;;&2vNtc6Y& zIt#6Ze5ufCv05@QStXEKq}f6$NhMN=K3cCromOweTP3LqE!JBn`C1big>=U5PhVy7 zc~=dTyIkc1tERs%h(t04Dk9P>iMinlr1m0#SR#}N1R`aeK`-y^mB$ziN|8W7m0}cY zb&BwuL`#}nA<$)~$i>Qts4%fmA`*wol;JY5+-?jH*D7SfMb(uFMq`n)rR`W-i?hgR zOsK40B=jBoufA_R#LPdhIaZ;5+hN=jIK_S;U z6VlU?@{}r3c)UuEhA5dzAr%M(5|LD*P(_Bt8wJ8@dYgpms*cVVJPnz&HF#d=?5L_v z;D0k{hUy0w2z^q%C>#`y(RaR%K7kYH`!x$Fg=p+LvzoA~#X7UYOxSgHht#aIrxH>+ z^L=F|>g;;E!`$ud?)I95wrTJ9xOd#`#yh>z_y!|89XoK~NUdkZB(CA!h-kJwizTaR_2=L-)V^3UB@ zn$`K?`4x9ihM`rKULcK(CZJyy(5UHGMm;Ua8VY%ZgELdOBlMNP7&x)-z3B3v{Hu{1 zAPm)-Fw{86jwl$r@s10(g}lGOmqTtr7JeGqC{)}S#0ZSIG1y4|7sZXCje+fl(rrH3 zt=`7|XSgUQYV=a8+N_pZo&WEEiK)3&s<%6>fvq-=+hf}*OquphOn4_;E`IRFY4F$) z4c?8@ZckS3h;76s92>EDLL5dn+D5$p9?2gD@*L_zK~Lt$R!UNV`_FfYI#TsXPPH|O zx>B314w@>dnxC-$DB=+lK9`snYA|`Hr>9-rCR4X-!p)2OBa=yxpP0Bfw2L}3h3ZZ2 waj!cuG-+}{z;khBIJO6la8C&W16OQefdk*XgEHy5JJw|N3=IVy_%=uMPouLzo&W#< diff --git a/src/vs/base/common/codicons.ts b/src/vs/base/common/codicons.ts index 8682ac8158a..95601fc7ac0 100644 --- a/src/vs/base/common/codicons.ts +++ b/src/vs/base/common/codicons.ts @@ -543,6 +543,9 @@ export namespace Codicon { export const typeHierarchySub = new Codicon('type-hierarchy-sub', { character: '\\ebba' }); export const typeHierarchySuper = new Codicon('type-hierarchy-super', { character: '\\ebbb' }); export const gitPullRequestCreate = new Codicon('git-pull-request-create', { character: '\\ebbc' }); + export const runAbove = new Codicon('run-above', { character: '\\ebbd' }); + export const runBelow = new Codicon('run-below', { character: '\\ebbe' }); + export const notebookTemplate = new Codicon('notebook-template', { character: '\\ebbf' }); export const dropDownButton = new Codicon('drop-down-button', Codicon.chevronDown.definition); } From 0354f334edfa4ae4227493e52e9e58e55f4c544c Mon Sep 17 00:00:00 2001 From: rebornix Date: Wed, 17 Feb 2021 11:43:40 -0800 Subject: [PATCH 276/325] remove unreached code. --- .../src/singlefolder-tests/notebook.test.ts | 305 ++---------------- 1 file changed, 23 insertions(+), 282 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts index c21be1935ab..e27ca9afcaa 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts @@ -6,7 +6,7 @@ import 'mocha'; import * as assert from 'assert'; import * as vscode from 'vscode'; -import { createRandomFile, asPromise, disposeAll, closeAllEditors, revertAllDirty } from '../utils'; +import { createRandomFile, asPromise, disposeAll, closeAllEditors, revertAllDirty, saveAllEditors } from '../utils'; // Since `workbench.action.splitEditor` command does await properly // Notebook editor/document events are not guaranteed to be sent to the ext host when promise resolves @@ -27,7 +27,7 @@ async function saveFileAndCloseAll(resource: vscode.Uri) { }); }); await vscode.commands.executeCommand('workbench.action.files.save'); - await vscode.commands.executeCommand('workbench.action.closeAllEditors'); + await closeAllEditors(); await documentClosed; } @@ -44,7 +44,7 @@ async function saveAllFilesAndCloseAll(resource: vscode.Uri | undefined) { }); }); await vscode.commands.executeCommand('workbench.action.files.saveAll'); - await vscode.commands.executeCommand('workbench.action.closeAllEditors'); + await closeAllEditors(); await documentClosed; } @@ -65,14 +65,6 @@ async function withEvent(event: vscode.Event, callback: (e: Promise) => await callback(e); } -function assertInitalState() { - // no-op unless we figure out why some documents are opened after the editor is closed - - // assert.strictEqual(vscode.window.activeNotebookEditor, undefined); - // assert.strictEqual(vscode.notebook.notebookDocuments.length, 0); - // assert.strictEqual(vscode.notebook.visibleNotebookEditors.length, 0); -} - suite('Notebook API tests', function () { const disposables: vscode.Disposable[] = []; @@ -209,48 +201,8 @@ suite('Notebook API tests', function () { })); }); - // test.only('crash', async function () { - // for (let i = 0; i < 200; i++) { - // let resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb')); - // await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - // await vscode.commands.executeCommand('workbench.action.revertAndCloseActiveEditor'); - - // resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './empty.vsctestnb')); - // await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - // await vscode.commands.executeCommand('workbench.action.revertAndCloseActiveEditor'); - // } - // }); - - // test.only('crash', async function () { - // for (let i = 0; i < 200; i++) { - // let resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb')); - // await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - // await vscode.commands.executeCommand('workbench.action.files.save'); - // await vscode.commands.executeCommand('workbench.action.closeAllEditors'); - // resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './empty.vsctestnb')); - // await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - // await vscode.commands.executeCommand('workbench.action.files.save'); - // await vscode.commands.executeCommand('workbench.action.closeAllEditors'); - // } - // }); - - test('document open/close event', async function () { - assertInitalState(); - - const resource = await createRandomFile('', undefined, '.vsctestnb'); - const firstDocumentOpen = asPromise(vscode.notebook.onDidOpenNotebookDocument); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - await firstDocumentOpen; - - const firstDocumentClose = asPromise(vscode.notebook.onDidCloseNotebookDocument); - await vscode.commands.executeCommand('workbench.action.closeAllEditors'); - await firstDocumentClose; - }); - test('shared document in notebook editors', async function () { - assertInitalState(); - - const resource = await createRandomFile('', undefined, '.vsctestnb'); + const resource = await createRandomFile(undefined, undefined, '.vsctestnb'); let counter = 0; const disposables: vscode.Disposable[] = []; disposables.push(vscode.notebook.onDidOpenNotebookDocument(() => { @@ -264,28 +216,24 @@ suite('Notebook API tests', function () { await splitEditor(); assert.strictEqual(counter, 1); - await vscode.commands.executeCommand('workbench.action.closeAllEditors'); + await closeAllEditors(); assert.strictEqual(counter, 0); disposables.forEach(d => d.dispose()); }); test('editor open/close event', async function () { - assertInitalState(); - const resource = await createRandomFile('', undefined, '.vsctestnb'); const firstEditorOpen = asPromise(vscode.window.onDidChangeVisibleNotebookEditors); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); await firstEditorOpen; const firstEditorClose = asPromise(vscode.window.onDidChangeVisibleNotebookEditors); - await vscode.commands.executeCommand('workbench.action.closeAllEditors'); + await closeAllEditors(); await firstEditorClose; }); test('editor open/close event 2', async function () { - assertInitalState(); - const resource = await createRandomFile('', undefined, '.vsctestnb'); let count = 0; const disposables: vscode.Disposable[] = []; @@ -299,13 +247,11 @@ suite('Notebook API tests', function () { await splitEditor(); assert.strictEqual(count, 2); - await vscode.commands.executeCommand('workbench.action.closeAllEditors'); + await closeAllEditors(); assert.strictEqual(count, 0); }); test('editor editing event 2', async function () { - assertInitalState(); - const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); @@ -373,12 +319,10 @@ suite('Notebook API tests', function () { // language: 'markdown' // }); - await vscode.commands.executeCommand('workbench.action.files.save'); - await vscode.commands.executeCommand('workbench.action.closeAllEditors'); + await saveAllFilesAndCloseAll(undefined); }); test('editor move cell event', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); @@ -408,19 +352,16 @@ suite('Notebook API tests', function () { ] }); - await vscode.commands.executeCommand('workbench.action.files.save'); - await vscode.commands.executeCommand('workbench.action.closeAllEditors'); + await saveAllEditors(); + await closeAllEditors(); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); const firstEditor = vscode.window.activeNotebookEditor; assert.strictEqual(firstEditor?.document.cells.length, 1); - - await vscode.commands.executeCommand('workbench.action.files.save'); - await vscode.commands.executeCommand('workbench.action.closeAllEditors'); + await saveAllFilesAndCloseAll(undefined); }); test('notebook editor active/visible', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); const firstEditor = vscode.window.activeNotebookEditor; @@ -449,12 +390,10 @@ suite('Notebook API tests', function () { assert.strictEqual(vscode.window.visibleNotebookEditors.length, 2); assert.strictEqual(secondEditor && vscode.window.visibleNotebookEditors.indexOf(secondEditor) >= 0, true); - await vscode.commands.executeCommand('workbench.action.files.save'); - await vscode.commands.executeCommand('workbench.action.closeAllEditors'); + await saveAllFilesAndCloseAll(undefined); }); test('notebook active editor change', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); const firstEditorOpen = asPromise(vscode.window.onDidChangeActiveNotebookEditor); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); @@ -468,7 +407,6 @@ suite('Notebook API tests', function () { }); test('change cell language', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); @@ -492,7 +430,6 @@ suite('Notebook API tests', function () { }); test('edit API (replaceCells)', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); @@ -513,7 +450,6 @@ suite('Notebook API tests', function () { }); test('edit API (replaceOutput, USE NotebookCellOutput-type)', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); @@ -542,7 +478,6 @@ suite('Notebook API tests', function () { }); test('edit API (replaceOutput)', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); @@ -564,7 +499,6 @@ suite('Notebook API tests', function () { }); test('edit API (replaceOutput, event)', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); @@ -589,8 +523,6 @@ suite('Notebook API tests', function () { }); test('edit API (replaceMetadata)', async function () { - - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); @@ -608,8 +540,6 @@ suite('Notebook API tests', function () { }); test('edit API (replaceMetadata, event)', async function () { - - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); @@ -629,7 +559,6 @@ suite('Notebook API tests', function () { }); test('edit API batch edits', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); @@ -648,7 +577,6 @@ suite('Notebook API tests', function () { }); test('edit API batch edits undo/redo', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); @@ -675,7 +603,6 @@ suite('Notebook API tests', function () { }); test('initialzation should not emit cell change events.', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); let count = 0; @@ -696,7 +623,6 @@ suite('Notebook API tests', function () { // suite('notebook workflow', () => { test('notebook open', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); @@ -718,7 +644,6 @@ suite('Notebook API tests', function () { }); test('notebook cell actions', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); @@ -792,7 +717,6 @@ suite('Notebook API tests', function () { }); test('notebook join cells', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); @@ -816,7 +740,6 @@ suite('Notebook API tests', function () { }); test('move cells will not recreate cells in ExtHost', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); @@ -832,36 +755,10 @@ suite('Notebook API tests', function () { assert.deepStrictEqual(activeCell, newActiveCell); await saveFileAndCloseAll(resource); - // TODO@rebornix, there are still some events order issue. - // assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.indexOf(newActiveCell!), 2); }); - // test.only('document metadata is respected', async function () { - // const resource = await createRandomFile('', undefined, '.vsctestnb'); - // await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - - // assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); - // const editor = vscode.window.activeNotebookEditor!; - - // assert.strictEqual(editor.document.cells.length, 1); - // editor.document.metadata.editable = false; - // await editor.edit(builder => builder.delete(0)); - // assert.strictEqual(editor.document.cells.length, 1, 'should not delete cell'); // Not editable, no effect - // await editor.edit(builder => builder.insert(0, 'test', 'python', vscode.CellKind.Code, [], undefined)); - // assert.strictEqual(editor.document.cells.length, 1, 'should not insert cell'); // Not editable, no effect - - // editor.document.metadata.editable = true; - // await editor.edit(builder => builder.delete(0)); - // assert.strictEqual(editor.document.cells.length, 0, 'should delete cell'); // Editable, it worked - // await editor.edit(builder => builder.insert(0, 'test', 'python', vscode.CellKind.Code, [], undefined)); - // assert.strictEqual(editor.document.cells.length, 1, 'should insert cell'); // Editable, it worked - - // // await vscode.commands.executeCommand('workbench.action.files.save'); - // await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); - // }); test('cell runnable metadata is respected', async () => { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); @@ -890,7 +787,6 @@ suite('Notebook API tests', function () { }); test('document runnable metadata is respected', async () => { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); @@ -918,14 +814,12 @@ suite('Notebook API tests', function () { assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked }); - await vscode.commands.executeCommand('workbench.action.files.save'); - await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); + await saveAllFilesAndCloseAll(undefined); }); // TODO@rebornix this is wrong, `await vscode.commands.executeCommand('notebook.execute');` doesn't wait until the workspace edit is applied test.skip('cell execute command takes arguments', async () => { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); @@ -935,12 +829,10 @@ suite('Notebook API tests', function () { await vscode.commands.executeCommand('notebook.execute'); assert.strictEqual(cell.outputs.length, 0, 'should not execute'); // not runnable, didn't work - await vscode.commands.executeCommand('workbench.action.files.save'); - await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); + await saveAllFilesAndCloseAll(undefined); }); test('cell execute command takes arguments 2', async () => { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); @@ -974,14 +866,10 @@ suite('Notebook API tests', function () { assert.strictEqual(vscode.window.activeNotebookEditor?.document.uri.fsPath, secondResource.fsPath); }); - await vscode.commands.executeCommand('workbench.action.files.save'); - await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); - await vscode.commands.executeCommand('workbench.action.files.save'); - await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); + await saveAllFilesAndCloseAll(undefined); }); test('document execute command takes arguments', async () => { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); @@ -1014,14 +902,10 @@ suite('Notebook API tests', function () { assert.strictEqual(vscode.window.activeNotebookEditor?.document.uri.fsPath, secondResource.fsPath); }); - await vscode.commands.executeCommand('workbench.action.files.save'); - await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); - await vscode.commands.executeCommand('workbench.action.files.save'); - await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); + await saveAllFilesAndCloseAll(undefined); }); test('cell execute and select kernel', async () => { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); @@ -1049,14 +933,12 @@ suite('Notebook API tests', function () { 'my second output' ]); - await vscode.commands.executeCommand('workbench.action.files.save'); - await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); + await saveAllFilesAndCloseAll(undefined); }); // }); // suite('notebook dirty state', () => { test('notebook open', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); @@ -1090,7 +972,6 @@ suite('Notebook API tests', function () { // suite('notebook undo redo', () => { test('notebook open', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); @@ -1132,115 +1013,7 @@ suite('Notebook API tests', function () { await saveFileAndCloseAll(resource); }); - // test.skip('execute and then undo redo', async function () { - // assertInitalState(); - // const resource = await createRandomFile('', undefined, '.vsctestnb'); - // await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - - // const cellsChangeEvent = getEventOncePromise(vscode.notebook.onDidChangeNotebookCells); - // await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); - // const cellChangeEventRet = await cellsChangeEvent; - // assert.strictEqual(cellChangeEventRet.document, vscode.window.activeNotebookEditor?.document); - // assert.strictEqual(cellChangeEventRet.changes.length, 1); - // assert.deepStrictEqual(cellChangeEventRet.changes[0], { - // start: 1, - // deletedCount: 0, - // deletedItems: [], - // items: [ - // vscode.window.activeNotebookEditor!.document.cells[1] - // ] - // }); - - // const secondCell = vscode.window.activeNotebookEditor!.document.cells[1]; - - // const moveCellEvent = getEventOncePromise(vscode.notebook.onDidChangeNotebookCells); - // await vscode.commands.executeCommand('notebook.cell.moveUp'); - // const moveCellEventRet = await moveCellEvent; - // assert.deepStrictEqual(moveCellEventRet, { - // document: vscode.window.activeNotebookEditor!.document, - // changes: [ - // { - // start: 1, - // deletedCount: 1, - // deletedItems: [secondCell], - // items: [] - // }, - // { - // start: 0, - // deletedCount: 0, - // deletedItems: [], - // items: [vscode.window.activeNotebookEditor?.document.cells[0]] - // } - // ] - // }); - - // const cellOutputChange = getEventOncePromise(vscode.notebook.onDidChangeCellOutputs); - // await vscode.commands.executeCommand('notebook.cell.execute'); - // const cellOutputsAddedRet = await cellOutputChange; - // assert.deepStrictEqual(cellOutputsAddedRet, { - // document: vscode.window.activeNotebookEditor!.document, - // cells: [vscode.window.activeNotebookEditor!.document.cells[0]] - // }); - // assert.strictEqual(cellOutputsAddedRet.cells[0].outputs.length, 1); - - // const cellOutputClear = getEventOncePromise(vscode.notebook.onDidChangeCellOutputs); - // await vscode.commands.executeCommand('undo'); - // const cellOutputsCleardRet = await cellOutputClear; - // assert.deepStrictEqual(cellOutputsCleardRet, { - // document: vscode.window.activeNotebookEditor!.document, - // cells: [vscode.window.activeNotebookEditor!.document.cells[0]] - // }); - // assert.strictEqual(cellOutputsAddedRet.cells[0].outputs.length, 0); - - // await saveFileAndCloseAll(resource); - // }); - - // }); - - // suite('notebook working copy', () => { - // test('notebook revert on close', async function () { - // const resource = await createRandomFile('', undefined, '.vsctestnb'); - // await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - // await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); - // assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.document.getText(), ''); - - // await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove'); - // await vscode.commands.executeCommand('default:type', { text: 'var abc = 0;' }); - - // // close active editor from command will revert the file - // await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); - // await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - // assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true); - // assert.strictEqual(vscode.window.activeNotebookEditor?.selection !== undefined, true); - // assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cells[0], vscode.window.activeNotebookEditor?.selection); - // assert.strictEqual(vscode.window.activeNotebookEditor?.selection?.document.getText(), 'test'); - - // await vscode.commands.executeCommand('workbench.action.files.save'); - // await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); - // }); - - // test('notebook revert', async function () { - // const resource = await createRandomFile('', undefined, '.vsctestnb'); - // await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - // await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); - // assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.document.getText(), ''); - - // await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove'); - // await vscode.commands.executeCommand('default:type', { text: 'var abc = 0;' }); - // await vscode.commands.executeCommand('workbench.action.files.revert'); - - // assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true); - // assert.strictEqual(vscode.window.activeNotebookEditor?.selection !== undefined, true); - // assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cells[0], vscode.window.activeNotebookEditor?.selection); - // assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cells.length, 1); - // assert.strictEqual(vscode.window.activeNotebookEditor?.selection?.document.getText(), 'test'); - - // await vscode.commands.executeCommand('workbench.action.files.saveAll'); - // await vscode.commands.executeCommand('workbench.action.closeAllEditors'); - // }); - test('multiple tabs: dirty + clean', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); @@ -1266,7 +1039,6 @@ suite('Notebook API tests', function () { }); test('multiple tabs: two dirty tabs and switching', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); @@ -1299,13 +1071,9 @@ suite('Notebook API tests', function () { assert.strictEqual(vscode.window.activeNotebookEditor?.selection?.document.getText(), ''); await saveAllFilesAndCloseAll(secondResource); - // await vscode.commands.executeCommand('workbench.action.files.saveAll'); - // await vscode.commands.executeCommand('workbench.action.closeAllEditors'); }); test('multiple tabs: different editors with same document', async function () { - assertInitalState(); - const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); const firstNotebookEditor = vscode.window.activeNotebookEditor; @@ -1321,18 +1089,11 @@ suite('Notebook API tests', function () { assert.notEqual(firstNotebookEditor, secondNotebookEditor); assert.strictEqual(firstNotebookEditor?.document, secondNotebookEditor?.document, 'split notebook editors share the same document'); - // assert.notEqual(firstNotebookEditor?.asWebviewUri(vscode.Uri.file('./hello.png')), secondNotebookEditor?.asWebviewUri(vscode.Uri.file('./hello.png'))); await saveAllFilesAndCloseAll(resource); - - // await vscode.commands.executeCommand('workbench.action.files.saveAll'); - // await vscode.commands.executeCommand('workbench.action.closeAllEditors'); }); - // }); - // suite('metadata', () => { test('custom metadata should be supported', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); @@ -1346,7 +1107,6 @@ suite('Notebook API tests', function () { // TODO@rebornix skip as it crashes the process all the time test.skip('custom metadata should be supported 2', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); @@ -1362,20 +1122,9 @@ suite('Notebook API tests', function () { await saveFileAndCloseAll(resource); }); - // }); - // suite('regression', () => { - // test('microsoft/vscode-github-issue-notebooks#26. Insert template cell in the new empty document', async function () { - // assertInitalState(); - // await vscode.commands.executeCommand('workbench.action.files.newUntitledFile', { "viewType": "notebookCoreTest" }); - // assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); - // assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.document.getText(), ''); - // assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.language, 'typescript'); - // await vscode.commands.executeCommand('workbench.action.closeAllEditors'); - // }); test('#106657. Opening a notebook from markers view is broken ', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); @@ -1393,7 +1142,6 @@ suite('Notebook API tests', function () { }); test.skip('Cannot open notebook from cell-uri with vscode.open-command', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); @@ -1411,7 +1159,6 @@ suite('Notebook API tests', function () { }); test('#97830, #97764. Support switch to other editor types', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); @@ -1429,12 +1176,11 @@ suite('Notebook API tests', function () { await vscode.commands.executeCommand('vscode.openWith', resource, 'default'); assert.strictEqual(vscode.window.activeTextEditor?.document.uri.path, resource.path); - await vscode.commands.executeCommand('workbench.action.closeAllEditors'); + await closeAllEditors(); }); // open text editor, pin, and then open a notebook test('#96105 - dirty editors', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'default'); const edit = new vscode.WorkspaceEdit(); @@ -1446,19 +1192,17 @@ suite('Notebook API tests', function () { assert.notEqual(vscode.window.activeNotebookEditor, undefined, 'notebook first'); // assert.notEqual(vscode.window.activeTextEditor, undefined); - await vscode.commands.executeCommand('workbench.action.closeAllEditors'); + await closeAllEditors(); }); test('#102411 - untitled notebook creation failed', async function () { - assertInitalState(); await vscode.commands.executeCommand('workbench.action.files.newUntitledFile', { viewType: 'notebookCoreTest' }); assert.notEqual(vscode.window.activeNotebookEditor, undefined, 'untitled notebook editor is not undefined'); - await vscode.commands.executeCommand('workbench.action.closeAllEditors'); + await closeAllEditors(); }); test('#102423 - copy/paste shares the same text buffer', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); @@ -1478,11 +1222,10 @@ suite('Notebook API tests', function () { assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.length, 2); assert.notEqual(vscode.window.activeNotebookEditor!.document.cells[0].document.getText(), vscode.window.activeNotebookEditor!.document.cells[1].document.getText()); - await vscode.commands.executeCommand('workbench.action.closeAllEditors'); + await closeAllEditors(); }); test('#116598, output items change event.', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); @@ -1510,7 +1253,6 @@ suite('Notebook API tests', function () { }); test('#115855 onDidSaveNotebookDocument', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); @@ -1533,7 +1275,6 @@ suite('Notebook API tests', function () { test('#116808, active kernel should not be undefined', async function () { - assertInitalState(); const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); @@ -1560,7 +1301,7 @@ suite('Notebook API tests', function () { // assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); // const uri = vscode.window.activeNotebookEditor!.asWebviewUri(vscode.Uri.file('./hello.png')); // assert.strictEqual(uri.scheme, 'vscode-webview-resource'); - // await vscode.commands.executeCommand('workbench.action.closeAllEditors'); + // await closeAllEditors(); // }); @@ -1585,6 +1326,6 @@ suite('Notebook API tests', function () { // await vscode.commands.executeCommand('notebook.cell.execute'); // await promise; - // await vscode.commands.executeCommand('workbench.action.closeAllEditors'); + // await closeAllEditors(); // }); }); From 086112d4967380a9d0f408d28326a29472f61a39 Mon Sep 17 00:00:00 2001 From: rebornix Date: Wed, 17 Feb 2021 12:08:58 -0800 Subject: [PATCH 277/325] move cell output tests to document. --- .../notebook.document.test.ts | 61 ++++++++++++ .../src/singlefolder-tests/notebook.test.ts | 93 ------------------- 2 files changed, 61 insertions(+), 93 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts index 0d5ecc671fa..e0a8912e0f6 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts @@ -232,4 +232,65 @@ suite('Notebook Document', function () { assert.strictEqual(data.changes[0].items[0], document.cells[0]); assert.strictEqual(data.changes[0].items[1], document.cells[1]); }); + + test('workspace edit API (appendNotebookCellOutput, replaceCellOutput, event)', async function () { + const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest'); + const document = await vscode.notebook.openNotebookDocument(uri); + + const outputChangeEvent = utils.asPromise(vscode.notebook.onDidChangeCellOutputs); + const edit = new vscode.WorkspaceEdit(); + const firstCellOutput = new vscode.NotebookCellOutput([new vscode.NotebookCellOutputItem('foo', 'bar')]); + edit.appendNotebookCellOutput(document.uri, 0, [firstCellOutput]); + const success = await vscode.workspace.applyEdit(edit); + const data = await outputChangeEvent; + + assert.strictEqual(success, true); + assert.strictEqual(document.cells.length, 1); + assert.strictEqual(document.cells[0].outputs.length, 1); + assert.deepStrictEqual(document.cells[0].outputs, [firstCellOutput]); + + assert.strictEqual(data.document === document, true); + assert.strictEqual(data.cells.length, 1); + assert.strictEqual(data.cells[0].outputs.length, 1); + assert.deepStrictEqual(data.cells[0].outputs, [firstCellOutput]); + + + { + const outputChangeEvent = utils.asPromise(vscode.notebook.onDidChangeCellOutputs); + const edit = new vscode.WorkspaceEdit(); + const secondCellOutput = new vscode.NotebookCellOutput([new vscode.NotebookCellOutputItem('foo', 'baz')]); + edit.appendNotebookCellOutput(document.uri, 0, [secondCellOutput]); + const success = await vscode.workspace.applyEdit(edit); + const data = await outputChangeEvent; + + assert.strictEqual(success, true); + assert.strictEqual(document.cells.length, 1); + assert.strictEqual(document.cells[0].outputs.length, 2); + assert.deepStrictEqual(document.cells[0].outputs, [firstCellOutput, secondCellOutput]); + + assert.strictEqual(data.document === document, true); + assert.strictEqual(data.cells.length, 1); + assert.strictEqual(data.cells[0].outputs.length, 2); + assert.deepStrictEqual(data.cells[0].outputs, [firstCellOutput, secondCellOutput]); + } + + { + const outputChangeEvent = utils.asPromise(vscode.notebook.onDidChangeCellOutputs); + const edit = new vscode.WorkspaceEdit(); + const thirdOutput = new vscode.NotebookCellOutput([new vscode.NotebookCellOutputItem('foo', 'baz1')]); + edit.replaceNotebookCellOutput(document.uri, 0, [thirdOutput]); + const success = await vscode.workspace.applyEdit(edit); + const data = await outputChangeEvent; + + assert.strictEqual(success, true); + assert.strictEqual(document.cells.length, 1); + assert.strictEqual(document.cells[0].outputs.length, 1); + assert.deepStrictEqual(document.cells[0].outputs, [thirdOutput]); + + assert.strictEqual(data.document === document, true); + assert.strictEqual(data.cells.length, 1); + assert.strictEqual(data.cells[0].outputs.length, 1); + assert.deepStrictEqual(data.cells[0].outputs, [thirdOutput]); + } + }); }); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts index e27ca9afcaa..c246577b062 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts @@ -429,99 +429,6 @@ suite('Notebook API tests', function () { await saveAllFilesAndCloseAll(resource); }); - test('edit API (replaceCells)', async function () { - const resource = await createRandomFile('', undefined, '.vsctestnb'); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - - const cellsChangeEvent = asPromise(vscode.notebook.onDidChangeNotebookCells); - await vscode.window.activeNotebookEditor!.edit(editBuilder => { - editBuilder.replaceCells(1, 0, [{ cellKind: vscode.NotebookCellKind.Code, language: 'javascript', source: 'test 2', outputs: [], metadata: undefined }]); - }); - - const cellChangeEventRet = await cellsChangeEvent; - assert.strictEqual(cellChangeEventRet.document === vscode.window.activeNotebookEditor?.document, true); - assert.strictEqual(cellChangeEventRet.document.isDirty, true); - assert.strictEqual(cellChangeEventRet.changes.length, 1); - assert.strictEqual(cellChangeEventRet.changes[0].start, 1); - assert.strictEqual(cellChangeEventRet.changes[0].deletedCount, 0); - assert.strictEqual(cellChangeEventRet.changes[0].items[0] === vscode.window.activeNotebookEditor!.document.cells[1], true); - - await saveAllFilesAndCloseAll(resource); - }); - - test('edit API (replaceOutput, USE NotebookCellOutput-type)', async function () { - const resource = await createRandomFile('', undefined, '.vsctestnb'); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - - await vscode.window.activeNotebookEditor!.edit(editBuilder => { - editBuilder.replaceCellOutput(0, [new vscode.NotebookCellOutput([ - new vscode.NotebookCellOutputItem('application/foo', 'bar'), - new vscode.NotebookCellOutputItem('application/json', { data: true }, { metadata: true }), - ])]); - }); - - const document = vscode.window.activeNotebookEditor?.document!; - assert.strictEqual(document.isDirty, true); - assert.strictEqual(document.cells.length, 1); - assert.strictEqual(document.cells[0].outputs.length, 1); - - // consuming is OLD api (for now) - const [output] = document.cells[0].outputs; - - assert.strictEqual(output.outputs.length, 2); - assert.strictEqual(output.outputs[0].mime, 'application/foo'); - assert.strictEqual(output.outputs[0].value, 'bar'); - assert.strictEqual(output.outputs[1].mime, 'application/json'); - assert.deepStrictEqual(output.outputs[1].value, { data: true }); - - await saveAllFilesAndCloseAll(undefined); - }); - - test('edit API (replaceOutput)', async function () { - const resource = await createRandomFile('', undefined, '.vsctestnb'); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - - await vscode.window.activeNotebookEditor!.edit(editBuilder => { - editBuilder.replaceCellOutput(0, [new vscode.NotebookCellOutput([ - new vscode.NotebookCellOutputItem('foo', 'bar') - ])]); - }); - - const document = vscode.window.activeNotebookEditor?.document!; - assert.strictEqual(document.isDirty, true); - assert.strictEqual(document.cells.length, 1); - assert.strictEqual(document.cells[0].outputs.length, 1); - assert.strictEqual(document.cells[0].outputs[0].outputs.length, 1); - assert.strictEqual(document.cells[0].outputs[0].outputs[0].mime, 'foo'); - assert.strictEqual(document.cells[0].outputs[0].outputs[0].value, 'bar'); - - await saveAllFilesAndCloseAll(undefined); - }); - - test('edit API (replaceOutput, event)', async function () { - const resource = await createRandomFile('', undefined, '.vsctestnb'); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - - const outputChangeEvent = asPromise(vscode.notebook.onDidChangeCellOutputs); - await vscode.window.activeNotebookEditor!.edit(editBuilder => { - editBuilder.replaceCellOutput(0, [new vscode.NotebookCellOutput([ - new vscode.NotebookCellOutputItem('foo', 'bar') - ])]); - }); - - const value = await outputChangeEvent; - assert.strictEqual(value.document === vscode.window.activeNotebookEditor?.document, true); - assert.strictEqual(value.document.isDirty, true); - assert.strictEqual(value.cells.length, 1); - assert.strictEqual(value.document.cells.length, 1); - assert.strictEqual(value.document.cells[0].outputs.length, 1); - assert.strictEqual(value.document.cells[0].outputs[0].outputs.length, 1); - assert.strictEqual(value.document.cells[0].outputs[0].outputs[0].mime, 'foo'); - assert.strictEqual(value.document.cells[0].outputs[0].outputs[0].value, 'bar'); - - await saveAllFilesAndCloseAll(undefined); - }); - test('edit API (replaceMetadata)', async function () { const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); From 608e8791ff194e81a10ac0d963471922ddc9b6e0 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 17 Feb 2021 13:24:33 -0800 Subject: [PATCH 278/325] Add back support for reading from clipboard in webviews (#116597) * Add back support for reading from clipboard in webviews Fixes #115925 This was blocked by 7d5052f50846a8d2d52106b782f6260ccd4f7deb. * Gate permissions checks to webview frames --- src/vs/code/electron-main/app.ts | 12 ++++++++++-- .../webview/electron-main/webviewMainService.ts | 10 +++++++--- src/vs/workbench/contrib/webview/browser/pre/main.js | 3 +++ .../contrib/webview/browser/webviewElement.ts | 1 + 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index d6a819dee64..6d03ad233a4 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -225,11 +225,19 @@ export class CodeApplication extends Disposable { this.nativeHostMainService?.openExternal(undefined, url); }); - session.defaultSession.setPermissionRequestHandler((webContents, permission /* 'media' | 'geolocation' | 'notifications' | 'midiSysex' | 'pointerLock' | 'fullscreen' | 'openExternal' */, callback) => { + const webviewFrameUrl = 'about:blank?webviewFrame'; + + session.defaultSession.setPermissionRequestHandler((_webContents, permission /* 'media' | 'geolocation' | 'notifications' | 'midiSysex' | 'pointerLock' | 'fullscreen' | 'openExternal' */, callback, details) => { + if (details.requestingUrl === webviewFrameUrl) { + return callback(permission === 'clipboard-read'); + } return callback(false); }); - session.defaultSession.setPermissionCheckHandler((webContents, permission /* 'media' */) => { + session.defaultSession.setPermissionCheckHandler((_webContents, permission /* 'media' */, _origin, details) => { + if (details.requestingUrl === webviewFrameUrl) { + return permission === 'clipboard-read'; + } return false; }); }); diff --git a/src/vs/platform/webview/electron-main/webviewMainService.ts b/src/vs/platform/webview/electron-main/webviewMainService.ts index dd3984d4ba5..ccce8561a33 100644 --- a/src/vs/platform/webview/electron-main/webviewMainService.ts +++ b/src/vs/platform/webview/electron-main/webviewMainService.ts @@ -35,12 +35,16 @@ export class WebviewMainService extends Disposable implements IWebviewManagerSer this.portMappingProvider = this._register(new WebviewPortMappingProvider(tunnelService)); const sess = session.fromPartition(webviewPartitionId); - sess.setPermissionRequestHandler((webContents, permission /* 'media' | 'geolocation' | 'notifications' | 'midiSysex' | 'pointerLock' | 'fullscreen' | 'openExternal' */, callback) => { + sess.setPermissionRequestHandler((_webContents, permission, callback) => { + if (permission === 'clipboard-read') { + return callback(true); + } + return callback(false); }); - sess.setPermissionCheckHandler((webContents, permission /* 'media' */) => { - return false; + sess.setPermissionCheckHandler((_webContents, permission /* 'media' */) => { + return permission === 'clipboard-read'; }); } diff --git a/src/vs/workbench/contrib/webview/browser/pre/main.js b/src/vs/workbench/contrib/webview/browser/pre/main.js index 2d4ac83084a..1288ef1abb5 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/main.js +++ b/src/vs/workbench/contrib/webview/browser/pre/main.js @@ -508,12 +508,15 @@ newFrame.setAttribute('id', 'pending-frame'); newFrame.setAttribute('frameborder', '0'); newFrame.setAttribute('sandbox', options.allowScripts ? 'allow-scripts allow-forms allow-same-origin allow-pointer-lock allow-downloads' : 'allow-same-origin allow-pointer-lock'); + newFrame.setAttribute('allow', options.allowScripts ? 'clipboard-read; clipboard-write;' : ''); if (host.fakeLoad) { // We should just be able to use srcdoc, but I wasn't // seeing the service worker applying properly. // Fake load an empty on the correct origin and then write real html // into it to get around this. newFrame.src = `./fake.html?id=${ID}`; + } else { + newFrame.src = `about:blank?webviewFrame`; } newFrame.style.cssText = 'display: block; margin: 0; overflow: hidden; position: absolute; width: 100%; height: 100%; visibility: hidden'; document.body.appendChild(newFrame); diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts index d006ebb3243..f6ff3b6e7be 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts @@ -92,6 +92,7 @@ export class IFrameWebview extends BaseWebview implements Web const element = document.createElement('iframe'); element.className = `webview ${options.customClasses || ''}`; element.sandbox.add('allow-scripts', 'allow-same-origin', 'allow-forms', 'allow-pointer-lock', 'allow-downloads'); + element.setAttribute('allow', 'clipboard-read; clipboard-write;'); element.style.border = 'none'; element.style.width = '100%'; element.style.height = '100%'; From 6e908f57c7ccdf82b953b1059f88868755264331 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 17 Feb 2021 22:32:31 +0100 Subject: [PATCH 279/325] add debug logging for configuration --- .../configuration/browser/configuration.ts | 26 ++++++++++++------- .../browser/configurationService.ts | 9 ++++--- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/services/configuration/browser/configuration.ts b/src/vs/workbench/services/configuration/browser/configuration.ts index 04f37bd3a1a..91d485e0233 100644 --- a/src/vs/workbench/services/configuration/browser/configuration.ts +++ b/src/vs/workbench/services/configuration/browser/configuration.ts @@ -22,6 +22,7 @@ import { IConfigurationModel } from 'vs/platform/configuration/common/configurat import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { hash } from 'vs/base/common/hash'; import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; +import { ILogService } from 'vs/platform/log/common/log'; export class UserConfiguration extends Disposable { @@ -38,6 +39,7 @@ export class UserConfiguration extends Disposable { private readonly scopes: ConfigurationScope[] | undefined, private readonly fileService: IFileService, private readonly uriIdentityService: IUriIdentityService, + private readonly logService: ILogService, ) { super(); this.userConfiguration.value = new UserSettings(this.userSettingsResource, this.scopes, uriIdentityService.extUri, this.fileService); @@ -56,7 +58,7 @@ export class UserConfiguration extends Disposable { const folder = this.uriIdentityService.extUri.dirname(this.userSettingsResource); const standAloneConfigurationResources: [string, URI][] = [TASKS_CONFIGURATION_KEY].map(name => ([name, this.uriIdentityService.extUri.joinPath(folder, `${name}.json`)])); - const fileServiceBasedConfiguration = new FileServiceBasedConfiguration(folder.toString(), [this.userSettingsResource], standAloneConfigurationResources, this.scopes, this.fileService, this.uriIdentityService); + const fileServiceBasedConfiguration = new FileServiceBasedConfiguration(folder.toString(), [this.userSettingsResource], standAloneConfigurationResources, this.scopes, this.fileService, this.uriIdentityService, this.logService); const configurationModel = await fileServiceBasedConfiguration.loadConfiguration(); this.userConfiguration.value = fileServiceBasedConfiguration; @@ -89,8 +91,9 @@ class FileServiceBasedConfiguration extends Disposable { private readonly settingsResources: URI[], private readonly standAloneConfigurationResources: [string, URI][], private readonly scopes: ConfigurationScope[] | undefined, - private fileService: IFileService, - private uriIdentityService: IUriIdentityService + private readonly fileService: IFileService, + private readonly uriIdentityService: IUriIdentityService, + private readonly logService: ILogService, ) { super(); this.allResources = [...this.settingsResources, ...this.standAloneConfigurationResources.map(([, resource]) => resource)]; @@ -107,9 +110,13 @@ class FileServiceBasedConfiguration extends Disposable { const resolveContents = async (resources: URI[]): Promise<(string | undefined)[]> => { return Promise.all(resources.map(async resource => { try { - const content = await this.fileService.readFile(resource); - return content.value.toString(); + const content = (await this.fileService.readFile(resource)).value.toString(); + if (!content) { + this.logService.debug(`Configuration file '${resource.toString()}' is empty`); + } + return content; } catch (error) { + this.logService.trace(`Error while resolving configuration file '${resource.toString()}': ${errors.getErrorMessage(error)}`); if ((error).fileOperationResult !== FileOperationResult.FILE_NOT_FOUND && (error).fileOperationResult !== FileOperationResult.FILE_NOT_DIRECTORY) { errors.onUnexpectedError(error); @@ -694,6 +701,7 @@ export class FolderConfiguration extends Disposable { private readonly workbenchState: WorkbenchState, fileService: IFileService, uriIdentityService: IUriIdentityService, + logService: ILogService, private readonly configurationCache: IConfigurationCache ) { super(); @@ -704,12 +712,12 @@ export class FolderConfiguration extends Disposable { this.folderConfiguration = this.cachedFolderConfiguration; whenProviderRegistered(workspaceFolder.uri, fileService) .then(() => { - this.folderConfiguration = this._register(this.createFileServiceBasedConfiguration(fileService, uriIdentityService)); + this.folderConfiguration = this._register(this.createFileServiceBasedConfiguration(fileService, uriIdentityService, logService)); this._register(this.folderConfiguration.onDidChange(e => this.onDidFolderConfigurationChange())); this.onDidFolderConfigurationChange(); }); } else { - this.folderConfiguration = this._register(this.createFileServiceBasedConfiguration(fileService, uriIdentityService)); + this.folderConfiguration = this._register(this.createFileServiceBasedConfiguration(fileService, uriIdentityService, logService)); this._register(this.folderConfiguration.onDidChange(e => this.onDidFolderConfigurationChange())); } } @@ -727,10 +735,10 @@ export class FolderConfiguration extends Disposable { this._onDidChange.fire(); } - private createFileServiceBasedConfiguration(fileService: IFileService, uriIdentityService: IUriIdentityService) { + private createFileServiceBasedConfiguration(fileService: IFileService, uriIdentityService: IUriIdentityService, logService: ILogService) { const settingsResources = [uriIdentityService.extUri.joinPath(this.configurationFolder, `${FOLDER_SETTINGS_NAME}.json`)]; const standAloneConfigurationResources: [string, URI][] = [TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY].map(name => ([name, uriIdentityService.extUri.joinPath(this.configurationFolder, `${name}.json`)])); - return new FileServiceBasedConfiguration(this.configurationFolder.toString(), settingsResources, standAloneConfigurationResources, WorkbenchState.WORKSPACE === this.workbenchState ? FOLDER_SCOPES : WORKSPACE_SCOPES, fileService, uriIdentityService); + return new FileServiceBasedConfiguration(this.configurationFolder.toString(), settingsResources, standAloneConfigurationResources, WorkbenchState.WORKSPACE === this.workbenchState ? FOLDER_SCOPES : WORKSPACE_SCOPES, fileService, uriIdentityService, logService); } private updateCache(): Promise { diff --git a/src/vs/workbench/services/configuration/browser/configurationService.ts b/src/vs/workbench/services/configuration/browser/configurationService.ts index fa4552e36f9..a21ce8f01ec 100644 --- a/src/vs/workbench/services/configuration/browser/configurationService.ts +++ b/src/vs/workbench/services/configuration/browser/configurationService.ts @@ -12,7 +12,7 @@ import { Queue, Barrier, runWhenIdle, Promises } from 'vs/base/common/async'; import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import { IWorkspaceContextService, Workspace as BaseWorkspace, WorkbenchState, IWorkspaceFolder, IWorkspaceFoldersChangeEvent, WorkspaceFolder, toWorkspaceFolder, isWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { ConfigurationModel, DefaultConfigurationModel, ConfigurationChangeEvent, AllKeysConfigurationChangeEvent, mergeChanges } from 'vs/platform/configuration/common/configurationModels'; -import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides, keyFromOverrideIdentifier, isConfigurationOverrides, IConfigurationData, IConfigurationValue, IConfigurationChange } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides, keyFromOverrideIdentifier, isConfigurationOverrides, IConfigurationData, IConfigurationValue, IConfigurationChange, ConfigurationTargetToString } from 'vs/platform/configuration/common/configuration'; import { Configuration } from 'vs/workbench/services/configuration/common/configurationModels'; import { FOLDER_CONFIG_FOLDER_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId, IConfigurationCache, machineSettingsSchemaId, LOCAL_MACHINE_SCOPES, IWorkbenchConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -104,7 +104,7 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat this.logService = logService; this._configuration = new Configuration(this.defaultConfiguration, new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ResourceMap(), new ConfigurationModel(), new ResourceMap(), this.workspace); this.cachedFolderConfigs = new ResourceMap(); - this.localUserConfiguration = this._register(new UserConfiguration(environmentService.settingsResource, remoteAuthority ? LOCAL_MACHINE_SCOPES : undefined, fileService, uriIdentityService)); + this.localUserConfiguration = this._register(new UserConfiguration(environmentService.settingsResource, remoteAuthority ? LOCAL_MACHINE_SCOPES : undefined, fileService, uriIdentityService, logService)); this._register(this.localUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onLocalUserConfigurationChanged(userConfiguration))); if (remoteAuthority) { const remoteUserConfiguration = this.remoteUserConfiguration = this._register(new RemoteUserConfiguration(remoteAuthority, configurationCache, fileService, uriIdentityService, remoteAgentService)); @@ -693,7 +693,7 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat return Promise.all([...folders.map(folder => { let folderConfiguration = this.cachedFolderConfigs.get(folder.uri); if (!folderConfiguration) { - folderConfiguration = new FolderConfiguration(folder, FOLDER_CONFIG_FOLDER_NAME, this.getWorkbenchState(), this.fileService, this.uriIdentityService, this.configurationCache); + folderConfiguration = new FolderConfiguration(folder, FOLDER_CONFIG_FOLDER_NAME, this.getWorkbenchState(), this.fileService, this.uriIdentityService, this.logService, this.configurationCache); this._register(folderConfiguration.onDidChange(() => this.onWorkspaceFolderConfigurationChanged(folder))); this.cachedFolderConfigs.set(folder.uri, this._register(folderConfiguration)); } @@ -796,6 +796,9 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat private triggerConfigurationChange(change: IConfigurationChange, previous: { data: IConfigurationData, workspace?: Workspace } | undefined, target: ConfigurationTarget): void { if (change.keys.length) { + if (target !== ConfigurationTarget.DEFAULT) { + this.logService.debug(`Configuration keys changed in ${ConfigurationTargetToString(target)} target`, ...change.keys); + } const configurationChangeEvent = new ConfigurationChangeEvent(change, previous, this._configuration, this.workspace); configurationChangeEvent.source = target; configurationChangeEvent.sourceConfig = this.getTargetConfiguration(target); From 6dad35394fa301abaeb7b743a102a293092186b1 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Wed, 17 Feb 2021 17:02:21 -0500 Subject: [PATCH 280/325] Update copyright year --- build/lib/electron.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/lib/electron.ts b/build/lib/electron.ts index beb1b571f52..06c8033edb4 100644 --- a/build/lib/electron.ts +++ b/build/lib/electron.ts @@ -32,7 +32,7 @@ export const config = { version: util.getElectronVersion(), productAppName: product.nameLong, companyName: 'Microsoft Corporation', - copyright: 'Copyright (C) 2019 Microsoft. All rights reserved', + copyright: 'Copyright (C) 2021 Microsoft. All rights reserved', darwinIcon: 'resources/darwin/code.icns', darwinBundleIdentifier: product.darwinBundleIdentifier, darwinApplicationCategoryType: 'public.app-category.developer-tools', From c484ebb065cab4fdabfc7c0fa9443abf8104884e Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Wed, 17 Feb 2021 15:01:05 -0800 Subject: [PATCH 281/325] chore: enable compression for crash reports Fixes https://github.com/microsoft/vscode/issues/115888 --- src/main.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.js b/src/main.js index 2584223e1d6..97961a64821 100644 --- a/src/main.js +++ b/src/main.js @@ -371,7 +371,8 @@ function configureCrashReporter() { companyName: companyName, productName: process.env['VSCODE_DEV'] ? `${productName} Dev` : productName, submitURL, - uploadToServer: !crashReporterDirectory + uploadToServer: !crashReporterDirectory, + compress: true }); } From c0b69b03a9b3680b56330c12ea9cdf004c262e55 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Feb 2021 16:33:10 -0800 Subject: [PATCH 282/325] Ensure runState is updated correctly --- .../src/singlefolder-tests/notebook.test.ts | 26 +++++++++++++++++++ .../api/common/extHostTypeConverters.ts | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts index c21be1935ab..86cd4915005 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts @@ -1546,6 +1546,32 @@ suite('Notebook API tests', function () { await saveAllFilesAndCloseAll(resource); }); + test('Numeric metadata should get updated correctly', async function () { + const resource = await createRandomFile('', undefined, '.vsctestnb'); + const document = await vscode.notebook.openNotebookDocument(resource); + + const edit = new vscode.WorkspaceEdit(); + const runStartTime = Date.now(); + const lastRunDuration = Date.now() + 1000; + const runState = vscode.NotebookCellRunState.Running; + const executionOrder = 1234; + const metadata = document.cells[0].metadata.with({ + ...document.cells[0].metadata, + runStartTime, + runState, + lastRunDuration, + executionOrder + }); + edit.replaceNotebookCellMetadata(document.uri, 0, metadata); + await vscode.workspace.applyEdit(edit); + + assert.strictEqual(document.cells[0].metadata.runStartTime, runStartTime); + assert.strictEqual(document.cells[0].metadata.lastRunDuration, lastRunDuration); + assert.strictEqual(document.cells[0].metadata.executionOrder, executionOrder); + assert.strictEqual(document.cells[0].metadata.runState, vscode.NotebookCellRunState.Running); + await saveAllFilesAndCloseAll(resource); + }); + // }); // suite('webview', () => { diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 1c0301a8ac2..bc0db6649e5 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -1419,7 +1419,7 @@ export namespace NotebookCellRange { export namespace NotebookCellMetadata { export function to(data: notebooks.NotebookCellMetadata): types.NotebookCellMetadata { - return new types.NotebookCellMetadata(data.editable, data.breakpointMargin, data.runnable, data.hasExecutionOrder, data.executionOrder, data.runStartTime, data.runStartTime, data.statusMessage, data.lastRunDuration, data.inputCollapsed, data.outputCollapsed, data.custom); + return new types.NotebookCellMetadata(data.editable, data.breakpointMargin, data.runnable, data.hasExecutionOrder, data.executionOrder, data.runState, data.runStartTime, data.statusMessage, data.lastRunDuration, data.inputCollapsed, data.outputCollapsed, data.custom); } } From 45ad634581b416b797d4148c027ffe3aac71d342 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Wed, 17 Feb 2021 12:36:10 -0800 Subject: [PATCH 283/325] testing: show placeholder text if providers don't discover any tests Fixes #115007 --- .../contrib/testing/browser/media/testing.css | 15 ++++++ .../testing/browser/testExplorerActions.ts | 19 +++++++ .../testing/browser/testing.contribution.ts | 4 +- .../testing/browser/testingExplorerView.ts | 52 +++++++++++++++++-- .../common/workspaceTestCollectionService.ts | 14 +++++ 5 files changed, 97 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/testing/browser/media/testing.css b/src/vs/workbench/contrib/testing/browser/media/testing.css index 5e3adce155b..52988718b5a 100644 --- a/src/vs/workbench/contrib/testing/browser/media/testing.css +++ b/src/vs/workbench/contrib/testing/browser/media/testing.css @@ -12,6 +12,7 @@ .test-explorer > .test-explorer-tree { flex-grow: 1; height: 0px; + position: relative; } .test-explorer .test-item { @@ -81,6 +82,20 @@ animation: codicon-spin 1.25s steps(30) infinite; } +.testing-no-test-placeholder { + display: none; + padding: 0 20px; + position: absolute; + left: 0; + right: 0; + top: 0; + z-index: 1; +} + +.testing-no-test-placeholder.visible { + display: block; +} + /** -- peek */ .monaco-editor .zone-widget.test-output-peek .zone-widget-container.peekview-widget { border-top-width: 2px; diff --git a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts index 62310f4dea3..6697a6c0d94 100644 --- a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts +++ b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts @@ -19,6 +19,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { ExtHostTestingResource } from 'vs/workbench/api/common/extHost.protocol'; import { ViewAction } from 'vs/workbench/browser/parts/views/viewPane'; import { FocusedViewContext } from 'vs/workbench/common/views'; +import { IExtensionsViewPaneContainer, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/contrib/extensions/common/extensions'; import * as icons from 'vs/workbench/contrib/testing/browser/icons'; import { TestingExplorerView, TestingExplorerViewModel } from 'vs/workbench/contrib/testing/browser/testingExplorerView'; import { TestExplorerViewMode, TestExplorerViewSorting, Testing } from 'vs/workbench/contrib/testing/common/constants'; @@ -30,6 +31,7 @@ import { ITestResult, ITestResultService } from 'vs/workbench/contrib/testing/co import { ITestService, waitForAllRoots, waitForAllTests } from 'vs/workbench/contrib/testing/common/testService'; import { IWorkspaceTestCollectionService } from 'vs/workbench/contrib/testing/common/workspaceTestCollectionService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; const category = localize('testing.category', 'Test'); @@ -828,3 +830,20 @@ export class DebugLastRun extends RunOrDebugLastRun { return service.runTests({ debug: true, tests: nodes.map(node => ({ testId: node.id, providerId: node.providerId })) }); } } + +export class SearchForTestExtension extends Action2 { + constructor() { + super({ + id: 'testing.searchForTestExtension', + title: localize('testing.searchForTestExtension', "Search for Test Extension"), + f1: false, + }); + } + + public async run(accessor: ServicesAccessor) { + const viewletService = accessor.get(IViewletService); + const viewlet = (await viewletService.openViewlet(EXTENSIONS_VIEWLET_ID, true))?.getViewPaneContainer() as IExtensionsViewPaneContainer; + viewlet.search('tag:testing @sort:installs'); + viewlet.focus(); + } +} diff --git a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts index 411a66f1fa6..3919c1f1500 100644 --- a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts +++ b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts @@ -51,7 +51,6 @@ const viewContainer = Registry.as(ViewContainerExtensio hideIfEmpty: true, }, ViewContainerLocation.Sidebar); - const viewsRegistry = Registry.as(ViewContainerExtensions.ViewsRegistry); viewsRegistry.registerViewWelcomeContent(Testing.ExplorerViewId, { @@ -80,7 +79,7 @@ viewsRegistry.registerViews([{ order: -999, containerIcon: testingViewIcon, // temporary until release, at which point we can show the welcome view: - when: ContextKeyExpr.greater(TestingContextKeys.providerCount.serialize(), 0), + when: ContextKeyExpr.greater(TestingContextKeys.providerCount.key, 0), }], viewContainer); registerAction2(Action.TestingViewAsListAction); @@ -105,6 +104,7 @@ registerAction2(Action.ReRunFailedTests); registerAction2(Action.DebugFailedTests); registerAction2(Action.ReRunLastRun); registerAction2(Action.DebugLastRun); +registerAction2(Action.SearchForTestExtension); registerAction2(CloseTestPeek); Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TestingContentProvider, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts index c65800ac901..a8d684e2ed4 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts @@ -7,13 +7,14 @@ import * as dom from 'vs/base/browser/dom'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import * as aria from 'vs/base/browser/ui/aria/aria'; +import { Button } from 'vs/base/browser/ui/button/button'; import { IIdentityProvider, IKeyboardNavigationLabelProvider, IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { DefaultKeyboardNavigationDelegate, IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; import { ICompressedTreeNode } from 'vs/base/browser/ui/tree/compressedObjectTreeModel'; import { ObjectTree } from 'vs/base/browser/ui/tree/objectTree'; import { ITreeEvent, ITreeFilter, ITreeNode, ITreeRenderer, ITreeSorter, TreeFilterResult, TreeVisibility } from 'vs/base/browser/ui/tree/tree'; import { Action, IAction, IActionViewItem } from 'vs/base/common/actions'; -import { DeferredPromise } from 'vs/base/common/async'; +import { DeferredPromise, RunOnceScheduler } from 'vs/base/common/async'; import { Color, RGBA } from 'vs/base/common/color'; import { throttle } from 'vs/base/common/decorators'; import { Event } from 'vs/base/common/event'; @@ -30,6 +31,7 @@ import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService import { localize } from 'vs/nls'; import { MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { MenuItemAction } from 'vs/platform/actions/common/actions'; +import { ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; @@ -42,6 +44,7 @@ import { IProgress, IProgressService, IProgressStep } from 'vs/platform/progress import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { foreground } from 'vs/platform/theme/common/colorRegistry'; +import { attachButtonStyler } from 'vs/platform/theme/common/styler'; import { IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService'; import { TestRunState } from 'vs/workbench/api/common/extHostTypes'; import { IResourceLabel, IResourceLabelOptions, IResourceLabelProps, ResourceLabels } from 'vs/workbench/browser/labels'; @@ -180,11 +183,35 @@ export class TestingExplorerView extends ViewPane { } } +class EmptyTestsWidget extends Disposable { + private readonly el: HTMLElement; + constructor( + container: HTMLElement, + @ICommandService commandService: ICommandService, + @IThemeService themeService: IThemeService, + ) { + super(); + const el = this.el = dom.append(container, dom.$('.testing-no-test-placeholder')); + const emptyParagraph = dom.append(el, dom.$('p')); + emptyParagraph.innerText = localize('testingNoTest', 'No tests have been found in this workspace yet.'); + const buttonLabel = localize('testingFindExtension', 'Find Test Extensions'); + const button = this._register(new Button(el, { title: buttonLabel })); + button.label = buttonLabel; + this._register(attachButtonStyler(button, themeService)); + this._register(button.onDidClick(() => commandService.executeCommand('testing.searchForTestExtension'))); + } + + public setVisible(isVisible: boolean) { + this.el.classList.toggle('visible', isVisible); + } +} + export class TestingExplorerViewModel extends Disposable { public tree: ObjectTree; private filter: TestsFilter; public projection!: ITestTreeProjection; + private readonly emptyTestsWidget: EmptyTestsWidget; private readonly _viewMode = TestingContextKeys.viewMode.bindTo(this.contextKeyService); private readonly _viewSorting = TestingContextKeys.viewSorting.bindTo(this.contextKeyService); @@ -226,6 +253,8 @@ export class TestingExplorerViewModel extends Disposable { listContainer: HTMLElement, onDidChangeVisibility: Event, private listener: TestSubscriptionListener | undefined, + @ICommandService commandService: ICommandService, + @IThemeService themeService: IThemeService, @ITestService private readonly testService: ITestService, @ITestExplorerFilterState filterState: TestExplorerFilterState, @IInstantiationService private readonly instantiationService: IInstantiationService, @@ -237,6 +266,7 @@ export class TestingExplorerViewModel extends Disposable { ) { super(); + this.emptyTestsWidget = this._register(instantiationService.createInstance(EmptyTestsWidget, listContainer)); this._viewMode.set(this.storageService.get('testing.viewMode', StorageScope.WORKSPACE, TestExplorerViewMode.Tree) as TestExplorerViewMode); this._viewSorting.set(this.storageService.get('testing.viewSorting', StorageScope.WORKSPACE, TestExplorerViewSorting.ByLocation) as TestExplorerViewSorting); @@ -428,6 +458,12 @@ export class TestingExplorerViewModel extends Disposable { } } + private shouldShowEmptyPlaceholder() { + return !!this.listener + && this.listener.subscription.busyProviders === 0 + && this.listener.subscription.isEmpty; + } + private updatePreferredProjection() { this.projection?.dispose(); if (!this.listener) { @@ -441,12 +477,18 @@ export class TestingExplorerViewModel extends Disposable { this.projection = this.instantiationService.createInstance(HierarchicalByLocationProjection, this.listener); } - this.projection.onUpdate(this.deferUpdate, this); - this.projection.applyTo(this.tree); + const scheduler = new RunOnceScheduler(() => this.applyProjectionChanges(), 200); + this.projection.onUpdate(() => { + if (!scheduler.isScheduled()) { + scheduler.schedule(); + } + }); + + this.applyProjectionChanges(); } - @throttle(200) - private deferUpdate() { + private applyProjectionChanges() { + this.emptyTestsWidget.setVisible(this.shouldShowEmptyPlaceholder()); this.projection.applyTo(this.tree); } diff --git a/src/vs/workbench/contrib/testing/common/workspaceTestCollectionService.ts b/src/vs/workbench/contrib/testing/common/workspaceTestCollectionService.ts index e38fb6d1ae6..dcd1f333174 100644 --- a/src/vs/workbench/contrib/testing/common/workspaceTestCollectionService.ts +++ b/src/vs/workbench/contrib/testing/common/workspaceTestCollectionService.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter } from 'vs/base/common/event'; +import { Iterable } from 'vs/base/common/iterator'; import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IWorkspaceContextService, IWorkspaceFolder, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; @@ -148,6 +149,19 @@ class TestSubscription extends Disposable { return [...this.collectionsForWorkspaces.values()].map(v => [v.folder, v.collection] as const); } + /** + * Returns whether there are any subscriptions with non-empty providers. + */ + public get isEmpty() { + for (const { collection } of this.collectionsForWorkspaces.values()) { + if (Iterable.some(collection.all, t => !!t.parent)) { + return false; + } + } + + return true; + } + constructor( @IWorkspaceContextService workspaceContext: IWorkspaceContextService, @ITestService private readonly testService: ITestService, From 00ca99f567200de13e3d876ff1cb5130b6f3b78b Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Wed, 17 Feb 2021 15:28:44 -0800 Subject: [PATCH 284/325] testing: fix not being able to type spaces in filter --- .../workbench/contrib/testing/browser/testingExplorerView.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts index a8d684e2ed4..a63407436f5 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts @@ -151,7 +151,10 @@ export class TestingExplorerView extends ViewPane { } private createFilterActionBar() { - const bar = new ActionBar(this.container, { actionViewItemProvider: action => this.getActionViewItem(action) }); + const bar = new ActionBar(this.container, { + actionViewItemProvider: action => this.getActionViewItem(action), + triggerKeys: { keyDown: false, keys: [] }, + }); bar.push(new Action(Testing.FilterActionId)); bar.getContainer().classList.add('testing-filter-action-bar'); return bar; From b09a71dce7876a948b9bfe10368629b95e1e4ee5 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Wed, 17 Feb 2021 16:30:31 -0800 Subject: [PATCH 285/325] testing: update test results api to spec Refs https://github.com/microsoft/vscode/issues/107467#issuecomment-780776814 --- src/vs/vscode.proposed.d.ts | 58 ++++++++++--- .../api/browser/mainThreadTesting.ts | 20 +++-- .../workbench/api/common/extHost.api.impl.ts | 4 +- .../workbench/api/common/extHost.protocol.ts | 4 +- src/vs/workbench/api/common/extHostTesting.ts | 42 +++++++-- .../testing/browser/testingDecorations.ts | 4 +- .../testing/browser/testingExplorerView.ts | 4 +- .../testing/browser/testingOutputPeek.ts | 4 +- .../contrib/testing/common/testCollection.ts | 28 +++++- .../testing/common/testResultService.ts | 87 +++++++++---------- .../test/common/testResultService.test.ts | 2 +- 11 files changed, 172 insertions(+), 85 deletions(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index ce9a5668450..7b75660c5bd 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -2203,24 +2203,17 @@ declare module 'vscode' { export function createDocumentTestObserver(document: TextDocument): TestObserver; /** - * The last or selected test run. Cleared when a new test run starts. - */ - export const testResults: TestResults | undefined; + * List of test results stored by VS Code, sorted in descnding + * order by their `completedAt` time. + */ + export const testResults: ReadonlyArray; /** - * Event that fires when the testResults are updated. - */ + * Event that fires when the {@link testResults} array is updated. + */ export const onDidChangeTestResults: Event; } - export interface TestResults { - /** - * The results from the latest test run. The array contains a snapshot of - * all tests involved in the run at the moment when it completed. - */ - readonly tests: ReadonlyArray | undefined; - } - export interface TestObserver { /** * List of tests returned by test provider for files in the workspace. @@ -2527,6 +2520,45 @@ declare module 'vscode' { location?: Location; } + /** + * TestResults can be provided to VS Code, or read from it. + * + * The results contain a 'snapshot' of the tests at the point when the test + * run is complete. Therefore, information such as {@link Location} instances + * may be out of date. If the test still exists in the workspace, consumers + * can use its `id` to correlate the result instance with the living test. + * + * @todo coverage and other info may eventually live here + */ + export interface TestResults { + /** + * Unix milliseconds timestamp at which the tests were completed. + */ + completedAt: number; + + /** + * List of test results. The items in this array are the items that + * were passed in the {@link test.runTests} method. + */ + results: ReadonlyArray>; + } + + /** + * A {@link TestItem} with an associated result, which appear or can be + * provided in {@link TestResult} interfaces. + */ + export interface TestItemWithResults extends TestItem { + /** + * Current result of the test. + */ + result: TestState; + + /** + * Optional list of nested tests for this item. + */ + children?: Readonly[]; + } + //#endregion //#region Opener service (https://github.com/microsoft/vscode/issues/109277) diff --git a/src/vs/workbench/api/browser/mainThreadTesting.ts b/src/vs/workbench/api/browser/mainThreadTesting.ts index 110becb9583..496ffe00d82 100644 --- a/src/vs/workbench/api/browser/mainThreadTesting.ts +++ b/src/vs/workbench/api/browser/mainThreadTesting.ts @@ -5,6 +5,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { isDefined } from 'vs/base/common/types'; import { URI, UriComponents } from 'vs/base/common/uri'; import { Range } from 'vs/editor/common/core/range'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; @@ -40,11 +41,20 @@ export class MainThreadTesting extends Disposable implements MainThreadTestingSh this._register(this.testService.onShouldSubscribe(args => this.proxy.$subscribeToTests(args.resource, args.uri))); this._register(this.testService.onShouldUnsubscribe(args => this.proxy.$unsubscribeFromTests(args.resource, args.uri))); - // const testCompleteListener = this._register(new MutableDisposable()); - // todo(@connor4312): reimplement, maybe - // this._register(resultService.onResultsChanged(results => { - // testCompleteListener.value = results.onComplete(() => this.proxy.$publishTestResults({ tests: [] })); - // })); + + const prevResults = resultService.results.map(r => r.toJSON()).filter(isDefined); + if (prevResults.length) { + this.proxy.$publishTestResults(prevResults); + } + + this._register(resultService.onResultsChanged(evt => { + if ('completed' in evt) { + const serialized = evt.completed.toJSON(); + if (serialized) { + this.proxy.$publishTestResults([serialized]); + } + } + })); testService.updateRootProviderCount(1); diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 155c978701a..b383152bc59 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -341,11 +341,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I }, get onDidChangeTestResults() { checkProposedApiEnabled(extension); - return extHostTesting.onLastResultsChanged; + return extHostTesting.onResultsChanged; }, get testResults() { checkProposedApiEnabled(extension); - return extHostTesting.lastResults; + return extHostTesting.results; }, }; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 2e330fd4ee5..007300b98ef 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -58,7 +58,7 @@ import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib import { DebugConfigurationProviderTriggerKind, WorkspaceTrustState } from 'vs/workbench/api/common/extHostTypes'; import { IAccessibilityInformation } from 'vs/platform/accessibility/common/accessibility'; import { IExtensionIdWithVersion } from 'vs/platform/userDataSync/common/extensionsStorageSync'; -import { InternalTestItem, InternalTestResults, ITestState, RunTestForProviderRequest, RunTestsRequest, TestIdWithProvider, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection'; +import { InternalTestItem, ITestState, RunTestForProviderRequest, RunTestsRequest, TestIdWithProvider, TestsDiff, ISerializedTestResults } from 'vs/workbench/contrib/testing/common/testCollection'; import { CandidatePort } from 'vs/workbench/services/remote/common/remoteExplorerService'; import { WorkspaceTrustStateChangeEvent } from 'vs/platform/workspace/common/workspaceTrust'; @@ -1853,7 +1853,7 @@ export interface ExtHostTestingShape { $unsubscribeFromTests(resource: ExtHostTestingResource, uri: UriComponents): void; $lookupTest(test: TestIdWithProvider): Promise; $acceptDiff(resource: ExtHostTestingResource, uri: UriComponents, diff: TestsDiff): void; - $publishTestResults(results: InternalTestResults): void; + $publishTestResults(results: ISerializedTestResults[]): void; } export interface MainThreadTestingShape { diff --git a/src/vs/workbench/api/common/extHostTesting.ts b/src/vs/workbench/api/common/extHostTesting.ts index e1c86d4975c..b24ae70ab53 100644 --- a/src/vs/workbench/api/common/extHostTesting.ts +++ b/src/vs/workbench/api/common/extHostTesting.ts @@ -9,6 +9,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { Emitter } from 'vs/base/common/event'; import { once } from 'vs/base/common/functional'; import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; +import { deepFreeze } from 'vs/base/common/objects'; import { isDefined } from 'vs/base/common/types'; import { URI, UriComponents } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; @@ -20,7 +21,7 @@ import { TestItem, TestState } from 'vs/workbench/api/common/extHostTypeConverte import { Disposable } from 'vs/workbench/api/common/extHostTypes'; import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace'; import { OwnedTestCollection, SingleUseTestCollection } from 'vs/workbench/contrib/testing/common/ownedTestCollection'; -import { AbstractIncrementalTestCollection, IncrementalChangeCollector, IncrementalTestCollectionItem, InternalTestItem, InternalTestItemWithChildren, InternalTestResults, RunTestForProviderRequest, TestDiffOpType, TestIdWithProvider, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection'; +import { AbstractIncrementalTestCollection, IncrementalChangeCollector, IncrementalTestCollectionItem, InternalTestItem, ISerializedTestResults, RunTestForProviderRequest, SerializedTestResultItem, TestDiffOpType, TestIdWithProvider, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection'; import type * as vscode from 'vscode'; const getTestSubscriptionKey = (resource: ExtHostTestingResource, uri: URI) => `${resource}:${uri.toString()}`; @@ -39,8 +40,8 @@ export class ExtHostTesting implements ExtHostTestingShape { private workspaceObservers: WorkspaceFolderTestObserverFactory; private textDocumentObservers: TextDocumentTestObserverFactory; - public onLastResultsChanged = this.resultsChangedEmitter.event; - public lastResults?: vscode.TestResults; + public onResultsChanged = this.resultsChangedEmitter.event; + public results: ReadonlyArray = []; constructor(@IExtHostRpcService rpc: IExtHostRpcService, @IExtHostDocumentsAndEditors private readonly documents: IExtHostDocumentsAndEditors, @IExtHostWorkspace private readonly workspace: IExtHostWorkspace) { this.proxy = rpc.getProxy(MainContext.MainThreadTesting); @@ -105,11 +106,15 @@ export class ExtHostTesting implements ExtHostTestingShape { * Updates test results shown to extensions. * @override */ - public $publishTestResults(results: InternalTestResults): void { - const convert = (item: InternalTestItemWithChildren): vscode.RequiredTestItem => - ({ ...TestItem.toShallow(item.item), children: item.children.map(convert) }); + public $publishTestResults(results: ISerializedTestResults[]): void { + this.results = Object.freeze( + results + .map(r => deepFreeze(convertTestResults(r))) + .concat(this.results) + .sort((a, b) => b.completedAt - a.completedAt) + .slice(0, 32), + ); - this.lastResults = { tests: results.tests.map(convert) }; this.resultsChangedEmitter.fire(); } @@ -350,6 +355,29 @@ export class ExtHostTesting implements ExtHostTestingShape { } } +const convertTestResultItem = (item: SerializedTestResultItem, byInternalId: Map): vscode.TestItemWithResults => ({ + ...TestItem.toShallow(item.item), + result: TestState.to(item.state), + children: item.children + .map(c => byInternalId.get(c)) + .filter(isDefined) + .map(c => convertTestResultItem(c, byInternalId)), +}); + +const convertTestResults = (r: ISerializedTestResults): vscode.TestResults => { + const roots: SerializedTestResultItem[] = []; + const byInternalId = new Map(); + for (const item of r.items) { + byInternalId.set(item.id, item); + if (item.direct) { + roots.push(item); + } + } + + return { completedAt: r.completedAt, results: roots.map(r => convertTestResultItem(r, byInternalId)) }; +}; + + /* * A class which wraps a vscode.TestItem that provides the ability to filter a TestItem's children * to only the children that are located in a certain vscode.Uri. diff --git a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts index 415b2ae90ad..54f94ebe446 100644 --- a/src/vs/workbench/contrib/testing/browser/testingDecorations.ts +++ b/src/vs/workbench/contrib/testing/browser/testingDecorations.ts @@ -26,9 +26,9 @@ import { BREAKPOINT_EDITOR_CONTRIBUTION_ID, IBreakpointEditorContribution } from import { testingRunAllIcon, testingRunIcon, testingStatesToIcons } from 'vs/workbench/contrib/testing/browser/icons'; import { TestingOutputPeekController } from 'vs/workbench/contrib/testing/browser/testingOutputPeek'; import { testMessageSeverityColors } from 'vs/workbench/contrib/testing/browser/theme'; -import { IncrementalTestCollectionItem, IRichLocation, ITestMessage } from 'vs/workbench/contrib/testing/common/testCollection'; +import { IncrementalTestCollectionItem, IRichLocation, ITestMessage, TestResultItem } from 'vs/workbench/contrib/testing/common/testCollection'; import { buildTestUri, TestUriType } from 'vs/workbench/contrib/testing/common/testingUri'; -import { ITestResultService, TestResultItem } from 'vs/workbench/contrib/testing/common/testResultService'; +import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService'; import { IMainThreadTestCollection, ITestService } from 'vs/workbench/contrib/testing/common/testService'; export class TestingDecorations extends Disposable implements IEditorContribution { diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts index a63407436f5..914cb37bec2 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts @@ -899,7 +899,7 @@ class TestRunProgress { } private updateProgress() { - const running = this.resultService.results.filter(r => !r.isComplete); + const running = this.resultService.results.filter(r => r.completedAt === undefined); if (!running.length) { this.setIdleText(this.resultService.results[0]?.counts); this.current?.deferred.complete(); @@ -948,7 +948,7 @@ class TestRunProgress { return; } - if (!result.isComplete) { + if (result.completedAt === undefined) { const badge = new ProgressBadge(() => localize('testBadgeRunning', 'Test run in progress')); this.badge.value = this.activityService.showViewActivity(Testing.ExplorerViewId, { badge, clazz: 'progress-badge' }); return; diff --git a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts index 3e3bb38e45a..b3715669718 100644 --- a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts +++ b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts @@ -31,11 +31,11 @@ import { EditorModel } from 'vs/workbench/common/editor'; import { testingPeekBorder } from 'vs/workbench/contrib/testing/browser/theme'; import { AutoOpenPeekViewWhen, getTestingConfiguration, TestingConfigKeys } from 'vs/workbench/contrib/testing/common/configuration'; import { Testing } from 'vs/workbench/contrib/testing/common/constants'; -import { ITestItem, ITestMessage, ITestState } from 'vs/workbench/contrib/testing/common/testCollection'; +import { ITestItem, ITestMessage, ITestState, TestResultItem } from 'vs/workbench/contrib/testing/common/testCollection'; import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys'; import { isFailedState } from 'vs/workbench/contrib/testing/common/testingStates'; import { buildTestUri, parseTestUri, TestUriType } from 'vs/workbench/contrib/testing/common/testingUri'; -import { ITestResult, ITestResultService, TestResultItem, TestResultItemChange, TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResultService'; +import { ITestResult, ITestResultService, TestResultItemChange, TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResultService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; interface ITestDto { diff --git a/src/vs/workbench/contrib/testing/common/testCollection.ts b/src/vs/workbench/contrib/testing/common/testCollection.ts index e42f8a207a9..0a08e9d4f37 100644 --- a/src/vs/workbench/contrib/testing/common/testCollection.ts +++ b/src/vs/workbench/contrib/testing/common/testCollection.ts @@ -79,12 +79,32 @@ export interface InternalTestItem { item: ITestItem; } -export interface InternalTestItemWithChildren extends InternalTestItem { - children: this[]; +/** + * Test result item used in the main thread. + */ +export interface TestResultItem extends IncrementalTestCollectionItem { + /** Current state of this test */ + state: ITestState; + /** Computed state based on children */ + computedState: TestRunState; + /** True if the test is outdated */ + retired: boolean; + /** True if the test was directly requested by the run (is not a child or parent) */ + direct?: true; } -export interface InternalTestResults { - tests: InternalTestItemWithChildren[]; +export type SerializedTestResultItem = Omit & { children: string[], retired: undefined }; + +/** + * Test results serialized for transport and storage. + */ +export interface ISerializedTestResults { + /** ID of these test results */ + id: string; + /** Time the results were compelted */ + completedAt: number; + /** Subset of test result items */ + items: SerializedTestResultItem[]; } export const enum TestDiffOpType { diff --git a/src/vs/workbench/contrib/testing/common/testResultService.ts b/src/vs/workbench/contrib/testing/common/testResultService.ts index 6cc3d553a54..ed6e98446a2 100644 --- a/src/vs/workbench/contrib/testing/common/testResultService.ts +++ b/src/vs/workbench/contrib/testing/common/testResultService.ts @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter, Event } from 'vs/base/common/event'; +import { Lazy } from 'vs/base/common/lazy'; +import { isDefined } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import { Range } from 'vs/editor/common/core/range'; @@ -13,7 +15,7 @@ import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storag import { TestRunState } from 'vs/workbench/api/common/extHostTypes'; import { IComputedStateAccessor, refreshComputedState } from 'vs/workbench/contrib/testing/common/getComputedState'; import { StoredValue } from 'vs/workbench/contrib/testing/common/storedValue'; -import { IncrementalTestCollectionItem, ITestState, RunTestsRequest } from 'vs/workbench/contrib/testing/common/testCollection'; +import { IncrementalTestCollectionItem, ISerializedTestResults, ITestState, RunTestsRequest, TestResultItem } from 'vs/workbench/contrib/testing/common/testCollection'; import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys'; import { statesInOrder } from 'vs/workbench/contrib/testing/common/testingStates'; import { IMainThreadTestCollection } from 'vs/workbench/contrib/testing/common/testService'; @@ -47,9 +49,10 @@ export interface ITestResult { readonly id: string; /** - * Gets whether the test run has finished. + * If the test is completed, the unix milliseconds time at which it was + * completed. If undefined, the test is still running. */ - readonly isComplete: boolean; + readonly completedAt: number | undefined; /** * Whether this test result is triggered from an auto run. @@ -70,7 +73,7 @@ export interface ITestResult { * Serializes the test result. Used to save and restore results * in the workspace. */ - toJSON(): ISerializedResults; + toJSON(): ISerializedTestResults | undefined; } export const makeEmptyCounts = () => { @@ -174,18 +177,6 @@ const makeNodeAndChildren = ( return mapped; }; -interface ISerializedResults { - id: string; - items: (Omit & { children: string[], retired: undefined })[]; -} - -export interface TestResultItem extends IncrementalTestCollectionItem { - state: ITestState; - computedState: TestRunState; - retired: boolean; - direct?: true; -} - /** * Results of a test. These are created when the test initially started running * and marked as "complete" when the run finishes. @@ -218,7 +209,7 @@ export class LiveTestResult implements ITestResult { private readonly completeEmitter = new Emitter(); private readonly changeEmitter = new Emitter(); - private _complete = false; + private _completedAt?: number; public readonly onChange = this.changeEmitter.event; public readonly onComplete = this.completeEmitter.event; @@ -231,8 +222,8 @@ export class LiveTestResult implements ITestResult { /** * @inheritdoc */ - public get isComplete() { - return this._complete; + public get completedAt() { + return this._completedAt; } /** @@ -387,29 +378,32 @@ export class LiveTestResult implements ITestResult { * Notifies the service that all tests are complete. */ public markComplete() { - if (this._complete) { + if (this._completedAt !== undefined) { throw new Error('cannot complete a test result multiple times'); } // un-queue any tests that weren't explicitly updated this.setAllToState(unsetState, t => t.state.state === TestRunState.Queued); - this._complete = true; + this._completedAt = Date.now(); this.completeEmitter.fire(); } /** * @inheritdoc */ - public toJSON(): ISerializedResults { - return { - id: this.id, - items: [...this.testByExtId.values()].map(entry => ({ - ...entry, - retired: undefined, - children: [...entry.children], - })), - }; + public toJSON(): ISerializedTestResults | undefined { + return this.completedAt ? this.doSerialize.getValue() : undefined; } + + private readonly doSerialize = new Lazy((): ISerializedTestResults => ({ + id: this.id, + completedAt: this.completedAt!, + items: [...this.testByExtId.values()].map(entry => ({ + ...entry, + retired: undefined, + children: [...entry.children], + })), + })); } /** @@ -429,7 +423,7 @@ class HydratedTestResult implements ITestResult { /** * @inheritdoc */ - public readonly isComplete = true; + public readonly completedAt: number; /** * @inheritdoc @@ -440,8 +434,9 @@ class HydratedTestResult implements ITestResult { private readonly byExtId = new Map(); - constructor(private readonly serialized: ISerializedResults) { + constructor(private readonly serialized: ISerializedTestResults) { this.id = serialized.id; + this.completedAt = serialized.completedAt; for (const item of serialized.items) { const cast: TestResultItem = { ...item, retired: true, children: new Set(item.children) }; @@ -472,7 +467,7 @@ class HydratedTestResult implements ITestResult { /** * @inheritdoc */ - public toJSON(): ISerializedResults { + public toJSON(): ISerializedTestResults { return this.serialized; } } @@ -545,7 +540,7 @@ export class TestResultService implements ITestResultService { public readonly onTestChanged = this.testChangeEmitter.event; private readonly isRunning: IContextKey; - private readonly serializedResults: StoredValue; + private readonly serializedResults: StoredValue; constructor(@IContextKeyService contextKeyService: IContextKeyService, @IStorageService storage: IStorageService) { this.isRunning = TestingContextKeys.isRunning.bindTo(contextKeyService); @@ -557,7 +552,10 @@ export class TestResultService implements ITestResultService { try { for (const value of this.serializedResults.get([])) { - this.results.push(new HydratedTestResult(value)); + // todo@connor4312: temp to migrate old insiders + if (value.completedAt) { + this.results.push(new HydratedTestResult(value)); + } } } catch (e) { // outdated structure @@ -609,7 +607,7 @@ export class TestResultService implements ITestResultService { const keep: ITestResult[] = []; const removed: ITestResult[] = []; for (const result of this.results) { - if (result.isComplete) { + if (result.completedAt !== undefined) { removed.push(result); } else { keep.push(result); @@ -617,20 +615,19 @@ export class TestResultService implements ITestResultService { } this.results = keep; - this.serializedResults.store(this.results.map(r => r.toJSON())); + this.serializedResults.store(this.results.map(r => r.toJSON()).filter(isDefined)); this.changeResultEmitter.fire({ removed }); } private onComplete(result: LiveTestResult) { // move the complete test run down behind any still-running ones - for (let i = 0; i < this.results.length - 1; i++) { - if (this.results[i].isComplete && !this.results[i + 1].isComplete) { - [this.results[i], this.results[i + 1]] = [this.results[i + 1], this.results[i]]; - } - } - - this.isRunning.set(!this.results[0]?.isComplete); - this.serializedResults.store(this.results.map(r => r.toJSON())); + this.resort(); + this.isRunning.set(this.results.length > 0 && this.results[0].completedAt === undefined); + this.serializedResults.store(this.results.map(r => r.toJSON()).filter(isDefined)); this.changeResultEmitter.fire({ completed: result }); } + + private resort() { + this.results.sort((a, b) => (b.completedAt ?? Number.MAX_SAFE_INTEGER) - (a.completedAt ?? Number.MAX_SAFE_INTEGER)); + } } diff --git a/src/vs/workbench/contrib/testing/test/common/testResultService.test.ts b/src/vs/workbench/contrib/testing/test/common/testResultService.test.ts index 86851a62f51..bf5deca24c4 100644 --- a/src/vs/workbench/contrib/testing/test/common/testResultService.test.ts +++ b/src/vs/workbench/contrib/testing/test/common/testResultService.test.ts @@ -161,7 +161,7 @@ suite('Workbench - Test Results Service', () => { assert.deepStrictEqual(actual, { ...expected, retired: true }); assert.deepStrictEqual(rehydrated.counts, r.counts); - assert.strictEqual(rehydrated.isComplete, true); + assert.strictEqual(typeof rehydrated.completedAt, 'number'); }); test('clears results but keeps ongoing tests', () => { From be6225f669b530838d998a7d3f086305e0eb9107 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 17 Feb 2021 16:47:20 -0800 Subject: [PATCH 286/325] Fix markdown cell focus indicators for notebooks (#116813) This change fixes the highlight indicators for markdown cells in norebooks. It also makes clicking on a markdown notebook cell focus it --- .../browser/diff/notebookTextDiffEditor.ts | 4 +++ .../notebook/browser/media/notebook.css | 12 +++---- .../notebook/browser/notebookBrowser.ts | 2 ++ .../notebook/browser/notebookEditorWidget.ts | 33 +++++++------------ .../view/renderers/backLayerWebView.ts | 12 +++++++ .../browser/view/renderers/cellRenderer.ts | 5 +++ .../browser/view/renderers/webviewPreloads.ts | 9 +++++ .../notebook/test/testNotebookEditor.ts | 3 ++ 8 files changed, 51 insertions(+), 29 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 81390f3d9ae..8112dbcedc2 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -610,6 +610,10 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD return cellInfo.diffElement.getCellByUri(cellInfo.cellUri); } + getCellById(cellId: string): IGenericCellViewModel | undefined { + throw new Error('Not implemented'); + } + removeInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: DiffNestedCellViewModel, displayOutput: ICellOutputViewModel, diffSide: DiffSide) { this._insetModifyQueueByOutputId.queue(displayOutput.model.outputId + (diffSide === DiffSide.Modified ? '-right' : 'left'), async () => { const activeWebview = diffSide === DiffSide.Modified ? this._modifiedWebview : this._originalWebview; diff --git a/src/vs/workbench/contrib/notebook/browser/media/notebook.css b/src/vs/workbench/contrib/notebook/browser/media/notebook.css index 543decf9627..2c47fe61743 100644 --- a/src/vs/workbench/contrib/notebook/browser/media/notebook.css +++ b/src/vs/workbench/contrib/notebook/browser/media/notebook.css @@ -291,8 +291,7 @@ } /* top border */ -.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-top:before, -.monaco-workbench .notebookOverlay .monaco-list .markdown-cell-row.focused .cell-inner-container:before { +.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-top:before { border-top: 1px solid transparent; } @@ -302,8 +301,7 @@ } /* bottom border */ -.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-bottom:before, -.monaco-workbench .notebookOverlay .monaco-list .markdown-cell-row.focused .cell-inner-container:after { +.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-bottom:before { border-bottom: 1px solid transparent; } @@ -312,8 +310,7 @@ border-right: 1px solid transparent; } -.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-top:before, -.monaco-workbench .notebookOverlay .monaco-list .markdown-cell-row.focused .cell-inner-container:before { +.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-top:before { top: 0; } @@ -321,8 +318,7 @@ left: 0; } -.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-bottom:before, -.monaco-workbench .notebookOverlay .monaco-list .markdown-cell-row.focused .cell-inner-container:after { +.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-bottom:before { bottom: 0px; } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index a67a588bbeb..1c3fea66478 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -162,6 +162,7 @@ export interface ICommonNotebookEditor { getCellOutputLayoutInfo(cell: IGenericCellViewModel): INotebookCellOutputLayoutInfo; triggerScroll(event: IMouseWheelEvent): void; getCellByInfo(cellInfo: ICommonCellInfo): IGenericCellViewModel; + getCellById(cellId: string): IGenericCellViewModel | undefined; focusNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): void; focusNextNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): void; updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, height: number, isInit: boolean): void; @@ -604,6 +605,7 @@ export interface INotebookEditor extends IEditor, ICommonNotebookEditor { getContribution(id: string): T; getCellByInfo(cellInfo: ICommonCellInfo): ICellViewModel; + getCellById(cellId: string): ICellViewModel | undefined; updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, height: number, isInit: boolean): void; } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 862443a95d5..2715b9f4f05 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -2080,6 +2080,10 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor return this.viewModel?.viewCells.find(vc => vc.handle === cellHandle) as CodeCellViewModel; } + getCellById(cellId: string): ICellViewModel | undefined { + return this.viewModel?.viewCells.find(vc => vc.id === cellId); + } + updateOutputHeight(cellInfo: ICommonCellInfo, output: ICellOutputViewModel, outputHeight: number, isInit: boolean): void { const cell = this.viewModel?.viewCells.find(vc => vc.handle === cellInfo.cellHandle); if (cell && cell instanceof CodeCellViewModel) { @@ -2090,24 +2094,21 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor } updateMarkdownCellHeight(cellId: string, height: number, isInit: boolean) { - const cell = this.viewModel?.viewCells.find(vc => vc.id === cellId); - + const cell = this.getCellById(cellId); if (cell && cell instanceof MarkdownCellViewModel) { cell.renderedMarkdownHeight = height; } } setMarkdownCellEditState(cellId: string, editState: CellEditState): void { - const cell = this.viewModel?.viewCells.find(vc => vc.id === cellId); - + const cell = this.getCellById(cellId); if (cell && cell instanceof MarkdownCellViewModel) { cell.editState = editState; } } markdownCellDragStart(cellId: string, ctx: { clientY: number }): void { - const cell = this.viewModel?.viewCells.find(vc => vc.id === cellId); - + const cell = this.getCellById(cellId); if (cell && cell instanceof MarkdownCellViewModel) { this._dndController?.startExplicitDrag(cell, ctx); } @@ -2380,8 +2381,6 @@ registerThemingParticipant((theme, collector) => { collector.addRule(` .monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-focus-indicator-top:before, .monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-focus-indicator-bottom:before, - .monaco-workbench .notebookOverlay .monaco-list:focus-within .markdown-cell-row.focused .cell-inner-container:not(.cell-editor-focus):before, - .monaco-workbench .notebookOverlay .monaco-list:focus-within .markdown-cell-row.focused .cell-inner-container:not(.cell-editor-focus):after, .monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-inner-container:not(.cell-editor-focus) .cell-focus-indicator-left:before, .monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-inner-container:not(.cell-editor-focus) .cell-focus-indicator-right:before { border-color: ${focusedCellBorderColor} !important; @@ -2390,9 +2389,7 @@ registerThemingParticipant((theme, collector) => { const inactiveFocusedBorderColor = theme.getColor(inactiveFocusedCellBorder); collector.addRule(` .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-top:before, - .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-bottom:before, - .monaco-workbench .notebookOverlay .monaco-list .markdown-cell-row.focused .cell-inner-container:not(.cell-editor-focus):before, - .monaco-workbench .notebookOverlay .monaco-list .markdown-cell-row.focused .cell-inner-container:not(.cell-editor-focus):after { + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-bottom:before { border-color: ${inactiveFocusedBorderColor} !important; }`); @@ -2611,15 +2608,12 @@ class DecorationCSSRules { const borderColor = this._resolveValue(this._providerArgs.options.borderColor); this._styleSheet.insertRule(`.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.${this.className} .cell-focus-indicator-top:before, - .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.${this.className} .cell-focus-indicator-bottom:before, - .monaco-workbench .notebookOverlay .monaco-list .${this.className}.markdown-cell-row.focused:before, - .monaco-workbench .notebookOverlay .monaco-list .${this.className}.markdown-cell-row.focused:after { + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.${this.className} .cell-focus-indicator-bottom:before { border-color: ${borderColor} !important; }`); this._styleSheet.insertRule(` - .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.${this.className} .cell-focus-indicator-bottom:before, - .monaco-workbench .notebookOverlay .monaco-list .markdown-cell-row.${this.className}:after { + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.${this.className} .cell-focus-indicator-bottom:before { content: ""; position: absolute; width: 100%; @@ -2629,8 +2623,7 @@ class DecorationCSSRules { `); this._styleSheet.insertRule(` - .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.${this.className} .cell-focus-indicator-top:before, - .monaco-workbench .notebookOverlay .monaco-list .markdown-cell-row.${this.className}:before { + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.${this.className} .cell-focus-indicator-top:before { content: ""; position: absolute; width: 100%; @@ -2640,9 +2633,7 @@ class DecorationCSSRules { // more specific rule for `.focused` can override existing rules this._styleSheet.insertRule(`.monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused.${this.className} .cell-focus-indicator-top:before, - .monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused.${this.className} .cell-focus-indicator-bottom:before, - .monaco-workbench .notebookOverlay .monaco-list:focus-within .markdown-cell-row.focused.${this.className}:before, - .monaco-workbench .notebookOverlay .monaco-list:focus-within .markdown-cell-row.focused.${this.className}:after { + .monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused.${this.className} .cell-focus-indicator-bottom:before { border-color: ${borderColor} !important; }`); } diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index bc6c5860802..2dd2fdf9fad 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -80,6 +80,12 @@ export interface IClickedDataUrlMessage { downloadName?: string; } +export interface IFocusMarkdownPreviewMessage { + __vscode_notebook_message: boolean; + type: 'focusMarkdownPreview'; + cellId: string; +} + export interface IToggleMarkdownPreviewMessage { __vscode_notebook_message: boolean; type: 'toggleMarkdownPreview'; @@ -264,6 +270,7 @@ export type FromWebviewMessage = | IBlurOutputMessage | ICustomRendererMessage | IClickedDataUrlMessage + | IFocusMarkdownPreviewMessage | IToggleMarkdownPreviewMessage | ICellDragStartMessage | ICellDragMessage @@ -783,6 +790,11 @@ var requirejs = (function() { this._onDidClickDataLink(data); } else if (data.type === 'customRendererMessage') { this._onMessage.fire({ message: data.message, forRenderer: data.rendererId }); + } else if (data.type === 'focusMarkdownPreview') { + const cell = this.notebookEditor.getCellById(data.cellId); + if (cell) { + this.notebookEditor.focusNotebookCell(cell, 'container'); + } } else if (data.type === 'toggleMarkdownPreview') { this.notebookEditor.setMarkdownCellEditState(data.cellId, CellEditState.Editing); } else if (data.type === 'cell-drag-start') { diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts index c976351d704..0e89bcdf663 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -400,6 +400,7 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR const deleteToolbar = disposables.add(this.createToolbar(titleToolbarContainer, 'cell-delete-toolbar')); deleteToolbar.setActions([this.instantiationService.createInstance(DeleteCellAction)]); + DOM.append(container, $('.cell-focus-indicator.cell-focus-indicator-top')); const focusIndicatorLeft = DOM.append(container, DOM.$('.cell-focus-indicator.cell-focus-indicator-side.cell-focus-indicator-left')); const focusIndicatorRight = DOM.append(container, DOM.$('.cell-focus-indicator.cell-focus-indicator-side.cell-focus-indicator-right')); @@ -557,6 +558,10 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR private updateForLayout(element: MarkdownCellViewModel, templateData: MarkdownCellRenderTemplate): void { // templateData.focusIndicatorLeft.style.height = `${element.layoutInfo.indicatorHeight}px`; templateData.focusIndicatorBottom.style.top = `${element.layoutInfo.totalHeight - BOTTOM_CELL_TOOLBAR_GAP - CELL_BOTTOM_MARGIN}px`; + + const focusSideHeight = element.layoutInfo.totalHeight - BOTTOM_CELL_TOOLBAR_GAP; + templateData.focusIndicatorLeft.style.height = `${focusSideHeight}px`; + templateData.focusIndicatorRight.style.height = `${focusSideHeight}px`; } disposeTemplate(templateData: MarkdownCellRenderTemplate): void { diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index 9874394d3e5..0b94c479326 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -700,6 +700,7 @@ function webviewPreloads() { previewContainerNode.style.top = top + 'px'; previewContainerNode.id = `${cellId}_preview`; previewContainerNode.classList.add('preview'); + previewContainerNode.addEventListener('dblclick', () => { vscode.postMessage({ __vscode_notebook_message: true, @@ -708,6 +709,14 @@ function webviewPreloads() { }); }); + previewContainerNode.addEventListener('click', () => { + vscode.postMessage({ + __vscode_notebook_message: true, + type: 'focusMarkdownPreview', + cellId, + }); + }); + previewContainerNode.setAttribute('draggable', 'true'); previewContainerNode.addEventListener('dragstart', e => { diff --git a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts index ec6bc22d6cd..3c7419a8563 100644 --- a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts @@ -83,6 +83,9 @@ export class TestNotebookEditor implements INotebookEditor { getCellByInfo(cellInfo: ICommonCellInfo): ICellViewModel { throw new Error('Method not implemented.'); } + getCellById(cellId: string): ICellViewModel { + throw new Error('Method not implemented.'); + } updateOutputHeight(cellInfo: ICommonCellInfo, output: ICellOutputViewModel, height: number, isInit: boolean): void { throw new Error('Method not implemented.'); } From 7160c4e7b50ceb84b39b1149f4c68518eacc80dc Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 17 Feb 2021 08:59:40 -0800 Subject: [PATCH 287/325] Fix suggest widget explainer commit character field having extra commas --- src/vs/editor/contrib/suggest/suggestWidgetDetails.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/suggest/suggestWidgetDetails.ts b/src/vs/editor/contrib/suggest/suggestWidgetDetails.ts index 9eed3c9900c..5adcbc39882 100644 --- a/src/vs/editor/contrib/suggest/suggestWidgetDetails.ts +++ b/src/vs/editor/contrib/suggest/suggestWidgetDetails.ts @@ -131,7 +131,7 @@ export class SuggestDetailsWidget { md += `score: ${item.score[0]}${item.word ? `, compared '${item.completion.filterText && (item.completion.filterText + ' (filterText)') || typeof item.completion.label === 'string' ? item.completion.label : item.completion.label.name}' with '${item.word}'` : ' (no prefix)'}\n`; md += `distance: ${item.distance}, see localityBonus-setting\n`; md += `index: ${item.idx}, based on ${item.completion.sortText && `sortText: "${item.completion.sortText}"` || 'label'}\n`; - md += `commit characters: ${item.completion.commitCharacters}\n`; + md += `commit characters: ${item.completion.commitCharacters?.join('')}\n`; documentation = new MarkdownString().appendCodeblock('empty', md); detail = `Provider: ${item.provider._debugDisplayName}`; } From 58f86d083d1bff567019e516aa8ff974d54954fa Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Feb 2021 16:52:03 -0800 Subject: [PATCH 288/325] Fixes to enure tests complete --- .../vscode-api-tests/src/singlefolder-tests/notebook.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts index 86cd4915005..921f9309716 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts @@ -1553,7 +1553,7 @@ suite('Notebook API tests', function () { const edit = new vscode.WorkspaceEdit(); const runStartTime = Date.now(); const lastRunDuration = Date.now() + 1000; - const runState = vscode.NotebookCellRunState.Running; + const runState = vscode.NotebookCellRunState.Success; const executionOrder = 1234; const metadata = document.cells[0].metadata.with({ ...document.cells[0].metadata, @@ -1568,7 +1568,7 @@ suite('Notebook API tests', function () { assert.strictEqual(document.cells[0].metadata.runStartTime, runStartTime); assert.strictEqual(document.cells[0].metadata.lastRunDuration, lastRunDuration); assert.strictEqual(document.cells[0].metadata.executionOrder, executionOrder); - assert.strictEqual(document.cells[0].metadata.runState, vscode.NotebookCellRunState.Running); + assert.strictEqual(document.cells[0].metadata.runState, vscode.NotebookCellRunState.Success); await saveAllFilesAndCloseAll(resource); }); From 714b41738e404d80e9f19c4f2622c35ce2f0df1b Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 17 Feb 2021 20:24:39 -0500 Subject: [PATCH 289/325] Adds id & version to extension context - #116906 --- src/vs/vscode.proposed.d.ts | 9 +++++++++ src/vs/workbench/api/common/extHostExtensionService.ts | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 7b75660c5bd..a0301e5b0fa 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -2156,6 +2156,15 @@ declare module 'vscode' { //#endregion + //#region https://github.com/microsoft/vscode/issues/116906 + + export interface ExtensionContext { + readonly extensionId: string; + readonly extensionVersion: string; + } + + //#endregion + //#region https://github.com/microsoft/vscode/issues/102091 export interface TextDocument { diff --git a/src/vs/workbench/api/common/extHostExtensionService.ts b/src/vs/workbench/api/common/extHostExtensionService.ts index 2274a4f12e7..47641e7993c 100644 --- a/src/vs/workbench/api/common/extHostExtensionService.ts +++ b/src/vs/workbench/api/common/extHostExtensionService.ts @@ -412,6 +412,14 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme get storageUri() { return that._storagePath.workspaceValue(extensionDescription); }, get globalStorageUri() { return that._storagePath.globalValue(extensionDescription); }, get extensionMode() { return extensionMode; }, + get extensionId() { + checkProposedApiEnabled(extensionDescription); + return extensionDescription.identifier.value; + }, + get extensionVersion() { + checkProposedApiEnabled(extensionDescription); + return extensionDescription.version; + }, get extensionRuntime() { checkProposedApiEnabled(extensionDescription); return that.extensionRuntime; From 473c7ddd50052000c8f3bf55a181c4858a54eb8b Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 17 Feb 2021 17:41:18 -0800 Subject: [PATCH 290/325] Ensure tests run to completion --- .../vscode-api-tests/src/singlefolder-tests/notebook.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts index 921f9309716..314bda6d018 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts @@ -1569,7 +1569,6 @@ suite('Notebook API tests', function () { assert.strictEqual(document.cells[0].metadata.lastRunDuration, lastRunDuration); assert.strictEqual(document.cells[0].metadata.executionOrder, executionOrder); assert.strictEqual(document.cells[0].metadata.runState, vscode.NotebookCellRunState.Success); - await saveAllFilesAndCloseAll(resource); }); // }); From cb95415caaaa4f622a7016a37ddccfa039ed27a1 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 17 Feb 2021 18:26:33 -0800 Subject: [PATCH 291/325] Revert back to old node-pty Worker threads don't appear to play nicely with asar which was causing only the bundled version of VS Code's terminal to break --- package.json | 2 +- remote/package.json | 2 +- remote/yarn.lock | 8 ++++---- yarn.lock | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index c6300383bea..b081a2aa694 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "native-is-elevated": "0.4.1", "native-keymap": "2.2.1", "native-watchdog": "1.3.0", - "node-pty": "0.11.0-beta1", + "node-pty": "0.10.0-beta19", "spdlog": "^0.11.1", "sudo-prompt": "9.1.1", "tas-client-umd": "0.1.2", diff --git a/remote/package.json b/remote/package.json index 86a8a64cb84..3d36902888e 100644 --- a/remote/package.json +++ b/remote/package.json @@ -13,7 +13,7 @@ "jschardet": "2.2.1", "minimist": "^1.2.5", "native-watchdog": "1.3.0", - "node-pty": "0.11.0-beta1", + "node-pty": "0.10.0-beta19", "spdlog": "^0.11.1", "tas-client-umd": "0.1.2", "vscode-nsfw": "1.2.9", diff --git a/remote/yarn.lock b/remote/yarn.lock index 35efe72cbb4..a264b79dde8 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -304,10 +304,10 @@ node-addon-api@^3.0.2: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.0.2.tgz#04bc7b83fd845ba785bb6eae25bc857e1ef75681" integrity sha512-+D4s2HCnxPd5PjjI0STKwncjXTUKKqm74MDMz9OPXavjsGmjkvwgLtA5yoxJUdmpj52+2u+RrXgPipahKczMKg== -node-pty@0.11.0-beta1: - version "0.11.0-beta1" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.11.0-beta1.tgz#961cf7ab56e0a689b71a19a46371ea090050f312" - integrity sha512-nHMB0K3LZTqjWv3X11XFdy/L4V2eMEk0RbmbVN02GPOkXdMy2NITI0px/x0JtNeIolRPq6r5hf5NUcNc2LJizw== +node-pty@0.10.0-beta19: + version "0.10.0-beta19" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.0-beta19.tgz#b7cbfba53f7b2a816efe8c9302dd083cc5874458" + integrity sha512-4UIOGMvpofUbe+ZniBUtY8zc/psMURSzbMonQgIhK7JlMQsUwcbkDIrKzStVLJX0FkeZpUNlsVtK7qqzHvrUZA== dependencies: nan "^2.14.0" diff --git a/yarn.lock b/yarn.lock index f1705f10ebd..8695942fcec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6672,10 +6672,10 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" -node-pty@0.11.0-beta1: - version "0.11.0-beta1" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.11.0-beta1.tgz#961cf7ab56e0a689b71a19a46371ea090050f312" - integrity sha512-nHMB0K3LZTqjWv3X11XFdy/L4V2eMEk0RbmbVN02GPOkXdMy2NITI0px/x0JtNeIolRPq6r5hf5NUcNc2LJizw== +node-pty@0.10.0-beta19: + version "0.10.0-beta19" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.0-beta19.tgz#b7cbfba53f7b2a816efe8c9302dd083cc5874458" + integrity sha512-4UIOGMvpofUbe+ZniBUtY8zc/psMURSzbMonQgIhK7JlMQsUwcbkDIrKzStVLJX0FkeZpUNlsVtK7qqzHvrUZA== dependencies: nan "^2.14.0" From a2a3bf27e9ecb46851f18c321c1af1e6272bdbe1 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 17 Feb 2021 17:25:54 -0800 Subject: [PATCH 292/325] Fix hover for notebook cell Hooks up hovers from markdown cells in webviews to correctly show the toolbars --- .../notebook/browser/media/notebook.css | 2 ++ .../notebook/browser/notebookBrowser.ts | 1 + .../view/renderers/backLayerWebView.ts | 25 +++++++++++++++++++ .../browser/view/renderers/cellRenderer.ts | 11 ++++++++ .../browser/view/renderers/webviewPreloads.ts | 15 +++++++++++ .../viewModel/markdownCellViewModel.ts | 10 ++++++++ 6 files changed, 64 insertions(+) diff --git a/src/vs/workbench/contrib/notebook/browser/media/notebook.css b/src/vs/workbench/contrib/notebook/browser/media/notebook.css index 2c47fe61743..6a72e8e9ae1 100644 --- a/src/vs/workbench/contrib/notebook/browser/media/notebook.css +++ b/src/vs/workbench/contrib/notebook/browser/media/notebook.css @@ -532,6 +532,7 @@ .monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list:focus-within > .monaco-scrollable-element > .monaco-list-rows:not(:hover) > .monaco-list-row.focused .cell-has-toolbar-actions .cell-title-toolbar, .monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover .cell-has-toolbar-actions .cell-title-toolbar, +.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .markdown-cell-hover.cell-has-toolbar-actions .cell-title-toolbar, .monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-has-toolbar-actions.cell-output-hover .cell-title-toolbar, .monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-has-toolbar-actions:hover .cell-title-toolbar { visibility: visible; @@ -637,6 +638,7 @@ .monaco-workbench .notebookOverlay .cell-list-top-cell-toolbar-container:focus-within, .monaco-workbench .notebookOverlay .cell-list-top-cell-toolbar-container:hover, .monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover .cell-bottom-toolbar-container, +.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .markdown-cell-hover .cell-bottom-toolbar-container, .monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list:focus-within > .monaco-scrollable-element > .monaco-list-rows:not(:hover) > .monaco-list-row.focused .cell-bottom-toolbar-container, .monaco-workbench .notebookOverlay.notebook-editor-editable > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container:focus-within { opacity: 1; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 1c3fea66478..886f9cfd0a6 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -784,6 +784,7 @@ export interface CellViewModelStateChangeEvent { foldingStateChanged?: boolean; contentChanged?: boolean; outputIsHoveredChanged?: boolean; + cellIsHoveredChanged?: boolean; } export function cellRangesEqual(a: ICellRange[], b: ICellRange[]) { diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index 2dd2fdf9fad..6be3811a493 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -20,6 +20,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { CellEditState, ICellOutputViewModel, ICommonCellInfo, ICommonNotebookEditor, IDisplayOutputLayoutUpdateRequest, IDisplayOutputViewModel, IGenericCellViewModel, IInsetRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { preloadsScriptStr } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads'; import { transformWebviewThemeVars } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewThemeMapping'; +import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel'; import { INotebookRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IWebviewService, WebviewContentPurpose, WebviewElement } from 'vs/workbench/contrib/webview/browser/webview'; @@ -86,6 +87,18 @@ export interface IFocusMarkdownPreviewMessage { cellId: string; } +export interface IMouseEnterMarkdownPreviewMessage { + __vscode_notebook_message: boolean; + type: 'mouseEnterMarkdownPreview'; + cellId: string; +} + +export interface IMouseLeaveMarkdownPreviewMessage { + __vscode_notebook_message: boolean; + type: 'mouseLeaveMarkdownPreview'; + cellId: string; +} + export interface IToggleMarkdownPreviewMessage { __vscode_notebook_message: boolean; type: 'toggleMarkdownPreview'; @@ -271,6 +284,8 @@ export type FromWebviewMessage = | ICustomRendererMessage | IClickedDataUrlMessage | IFocusMarkdownPreviewMessage + | IMouseEnterMarkdownPreviewMessage + | IMouseLeaveMarkdownPreviewMessage | IToggleMarkdownPreviewMessage | ICellDragStartMessage | ICellDragMessage @@ -797,6 +812,16 @@ var requirejs = (function() { } } else if (data.type === 'toggleMarkdownPreview') { this.notebookEditor.setMarkdownCellEditState(data.cellId, CellEditState.Editing); + } else if (data.type === 'mouseEnterMarkdownPreview') { + const cell = this.notebookEditor.getCellById(data.cellId); + if (cell instanceof MarkdownCellViewModel) { + cell.cellIsHovered = true; + } + } else if (data.type === 'mouseLeaveMarkdownPreview') { + const cell = this.notebookEditor.getCellById(data.cellId); + if (cell instanceof MarkdownCellViewModel) { + cell.cellIsHovered = false; + } } else if (data.type === 'cell-drag-start') { this.notebookEditor.markdownCellDragStart(data.cellId, data.position); } else if (data.type === 'cell-drag') { diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts index 0e89bcdf663..672cf0180cd 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -534,6 +534,13 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR this.updateForLayout(element, templateData); })); + this.updateForHover(element, templateData); + elementDisposables.add(element.onDidChangeState(e => { + if (e.cellIsHoveredChanged) { + this.updateForHover(element, templateData); + } + })); + // render toolbar first this.setupCellToolbarActions(templateData, elementDisposables); @@ -564,6 +571,10 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR templateData.focusIndicatorRight.style.height = `${focusSideHeight}px`; } + private updateForHover(element: MarkdownCellViewModel, templateData: MarkdownCellRenderTemplate): void { + templateData.container.classList.toggle('markdown-cell-hover', element.cellIsHovered); + } + disposeTemplate(templateData: MarkdownCellRenderTemplate): void { templateData.disposables.clear(); } diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index 0b94c479326..66492cc99c3 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -717,6 +717,21 @@ function webviewPreloads() { }); }); + previewContainerNode.addEventListener('mouseenter', () => { + vscode.postMessage({ + __vscode_notebook_message: true, + type: 'mouseEnterMarkdownPreview', + cellId, + }); + }); + previewContainerNode.addEventListener('mouseleave', () => { + vscode.postMessage({ + __vscode_notebook_message: true, + type: 'mouseLeaveMarkdownPreview', + cellId, + }); + }); + previewContainerNode.setAttribute('draggable', 'true'); previewContainerNode.addEventListener('dragstart', e => { diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel.ts index eae9ae0070c..dd382054f84 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel.ts @@ -69,6 +69,16 @@ export class MarkdownCellViewModel extends BaseCellViewModel implements ICellVie this._hoveringOutput = v; } + private _hoveringCell = false; + public get cellIsHovered(): boolean { + return this._hoveringCell; + } + + public set cellIsHovered(v: boolean) { + this._hoveringCell = v; + this._onDidChangeState.fire({ cellIsHoveredChanged: true }); + } + constructor( readonly viewType: string, readonly model: NotebookCellTextModel, From b0360851d4e2a96811e5547fd4590e956d05ea75 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 17 Feb 2021 17:26:24 -0800 Subject: [PATCH 293/325] Mark events fields readonly --- .../notebook/browser/notebookBrowser.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 886f9cfd0a6..192e9bd0c68 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -776,15 +776,15 @@ export enum CursorAtBoundary { } export interface CellViewModelStateChangeEvent { - metadataChanged?: boolean; - selectionChanged?: boolean; - focusModeChanged?: boolean; - editStateChanged?: boolean; - languageChanged?: boolean; - foldingStateChanged?: boolean; - contentChanged?: boolean; - outputIsHoveredChanged?: boolean; - cellIsHoveredChanged?: boolean; + readonly metadataChanged?: boolean; + readonly selectionChanged?: boolean; + readonly focusModeChanged?: boolean; + readonly editStateChanged?: boolean; + readonly languageChanged?: boolean; + readonly foldingStateChanged?: boolean; + readonly contentChanged?: boolean; + readonly outputIsHoveredChanged?: boolean; + readonly cellIsHoveredChanged?: boolean; } export function cellRangesEqual(a: ICellRange[], b: ICellRange[]) { From 4af885c61211178a6f83a74bd149bcf5f906c015 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 17 Feb 2021 19:21:17 -0800 Subject: [PATCH 294/325] Take `string` kind in `_executeCodeActionProvider` fixes mjbvz/vscode-folder-source-actions#3 Previously `_executeCodeActionProvider` took a serialized `CodeActionKind`. However this started failing a few versions back, likely by the refactorings for stricter command argument serialization (f3efe70c9a061955ffb50c61fd5ec5801b614910) Instead, update it to take a string (the `kind.value`). This is a breaking api change but considering this parameter is not widely used and has been broken for a few releases now, I think it makes sense to standardize things. A string fits better with our other commands --- src/vs/editor/contrib/codeAction/codeAction.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/contrib/codeAction/codeAction.ts b/src/vs/editor/contrib/codeAction/codeAction.ts index 25b7687bc4a..3fc3033b397 100644 --- a/src/vs/editor/contrib/codeAction/codeAction.ts +++ b/src/vs/editor/contrib/codeAction/codeAction.ts @@ -223,8 +223,7 @@ function getDocumentation( return undefined; } -CommandsRegistry.registerCommand('_executeCodeActionProvider', async function (accessor, ...args): Promise> { - const [resource, rangeOrSelection, kind, itemResolveCount] = args; +CommandsRegistry.registerCommand('_executeCodeActionProvider', async function (accessor, resource: URI, rangeOrSelection: Range | Selection, kind?: string, itemResolveCount?: number): Promise> { if (!(resource instanceof URI)) { throw illegalArgument(); } @@ -244,14 +243,14 @@ CommandsRegistry.registerCommand('_executeCodeActionProvider', async function (a throw illegalArgument(); } + const include = typeof kind === 'string' ? new CodeActionKind(kind) : undefined; const codeActionSet = await getCodeActions( model, validatedRangeOrSelection, - { type: modes.CodeActionTriggerType.Manual, filter: { includeSourceActions: true, include: kind && kind.value ? new CodeActionKind(kind.value) : undefined } }, + { type: modes.CodeActionTriggerType.Manual, filter: { includeSourceActions: true, include } }, Progress.None, CancellationToken.None); - const resolving: Promise[] = []; const resolveCount = Math.min(codeActionSet.validActions.length, typeof itemResolveCount === 'number' ? itemResolveCount : 0); for (let i = 0; i < resolveCount; i++) { From 6eaef7d42f982a0e9b22ac465245fc2c27721fd0 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 17 Feb 2021 19:42:08 -0800 Subject: [PATCH 295/325] Add postNotebookMessage helper function (#116909) This adds a new helper function called `postNotebookMessage` in the notebook webview. This method both reduces code duplication and enforces better typing As a result of the stricter typing, I had to clean up a few property annotations and their usages --- .../view/renderers/backLayerWebView.ts | 18 ++- .../browser/view/renderers/webviewPreloads.ts | 113 ++++++------------ 2 files changed, 49 insertions(+), 82 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index 6be3811a493..7d6765fc046 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as DOM from 'vs/base/browser/dom'; import { VSBuffer } from 'vs/base/common/buffer'; import { Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -36,9 +35,9 @@ export interface IDimensionMessage { __vscode_notebook_message: boolean; type: 'dimension'; id: string; - init: boolean; - data: DOM.Dimension; - isOutput: boolean; + init?: boolean; + data: { height: number }; + isOutput?: boolean; } export interface IMouseEnterMessage { @@ -77,7 +76,7 @@ export interface IBlurOutputMessage { export interface IClickedDataUrlMessage { __vscode_notebook_message: boolean; type: 'clicked-data-url'; - data: string; + data: string | ArrayBuffer | null; downloadName?: string; } @@ -130,6 +129,10 @@ export interface ICellDragEndMessage { readonly clientY: number; }; } +export interface IInitializedMarkdownPreviewMessage { + readonly __vscode_notebook_message: boolean; + readonly type: 'initializedMarkdownPreview'; +} export interface IClearMessage { type: 'clear'; @@ -290,6 +293,7 @@ export type FromWebviewMessage = | ICellDragStartMessage | ICellDragMessage | ICellDragEndMessage + | IInitializedMarkdownPreviewMessage ; export type ToWebviewMessage = | IClearMessage @@ -841,6 +845,10 @@ var requirejs = (function() { } private async _onDidClickDataLink(event: IClickedDataUrlMessage): Promise { + if (typeof event.data !== 'string') { + return; + } + const [splitStart, splitData] = event.data.split(';base64,'); if (!splitData || !splitStart) { return; diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index 66492cc99c3..cba45be0a7a 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -5,8 +5,8 @@ import type { Event } from 'vs/base/common/event'; import type { IDisposable } from 'vs/base/common/lifecycle'; -import { ICellDragEndMessage, ICellDragMessage, ICellDragStartMessage, ToWebviewMessage } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView'; import { RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { FromWebviewMessage, IBlurOutputMessage, ICellDragEndMessage, ICellDragMessage, ICellDragStartMessage, IClickedDataUrlMessage, ICustomRendererMessage, IDimensionMessage, IFocusMarkdownPreviewMessage, IMouseEnterMarkdownPreviewMessage, IMouseEnterMessage, IMouseLeaveMarkdownPreviewMessage, IMouseLeaveMessage, IToggleMarkdownPreviewMessage, IWheelMessage, ToWebviewMessage } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView'; // !! IMPORTANT !! everything must be in-line within the webviewPreloads // function. Imports are not allowed. This is stringifies and injected into @@ -60,9 +60,7 @@ function webviewPreloads() { }; const handleDataUrl = async (data: string | ArrayBuffer | null, downloadName: string) => { - vscode.postMessage({ - __vscode_notebook_message: true, - type: 'clicked-data-url', + postNotebookMessage('clicked-data-url', { data, downloadName }); @@ -146,9 +144,7 @@ function webviewPreloads() { if (entry.target.id === id && entry.contentRect) { if (entry.contentRect.height !== 0) { entry.target.style.padding = `${__outputNodePadding__}px ${__outputNodePadding__}px ${__outputNodePadding__}px ${__outputNodeLeftPadding__}px`; - vscode.postMessage({ - __vscode_notebook_message: true, - type: 'dimension', + postNotebookMessage('dimension', { id: id, data: { height: entry.contentRect.height + __outputNodePadding__ * 2 @@ -157,9 +153,7 @@ function webviewPreloads() { }); } else { entry.target.style.padding = `0px`; - vscode.postMessage({ - __vscode_notebook_message: true, - type: 'dimension', + postNotebookMessage('dimension', { id: id, data: { height: entry.contentRect.height @@ -201,10 +195,7 @@ function webviewPreloads() { if (event.defaultPrevented || scrollWillGoToParent(event)) { return; } - - vscode.postMessage({ - __vscode_notebook_message: true, - type: 'did-scroll-wheel', + postNotebookMessage('did-scroll-wheel', { payload: { deltaMode: event.deltaMode, deltaX: event.deltaX, @@ -228,9 +219,7 @@ function webviewPreloads() { const element = document.createElement('div'); element.tabIndex = 0; element.addEventListener('focus', () => { - vscode.postMessage({ - __vscode_notebook_message: true, - type: 'focus-editor', + postNotebookMessage('focus-editor', { id: outputId, focusNext }); @@ -246,19 +235,13 @@ function webviewPreloads() { function addMouseoverListeners(element: HTMLElement, outputId: string): void { element.addEventListener('mouseenter', () => { - vscode.postMessage({ - __vscode_notebook_message: true, - type: 'mouseenter', + postNotebookMessage('mouseenter', { id: outputId, - data: {} }); }); element.addEventListener('mouseleave', () => { - vscode.postMessage({ - __vscode_notebook_message: true, - type: 'mouseleave', + postNotebookMessage('mouseleave', { id: outputId, - data: {} }); }); } @@ -345,9 +328,7 @@ function webviewPreloads() { return { postMessage(message: unknown) { - vscode.postMessage({ - __vscode_notebook_message: true, - type: 'customRendererMessage', + postNotebookMessage('customRendererMessage', { rendererId: namespace, message, }); @@ -418,10 +399,7 @@ function webviewPreloads() { createMarkdownPreview(cell.cellId, cell.content, -10000); } - vscode.postMessage({ - __vscode_notebook_message: true, - type: 'initializedMarkdownPreview', - }); + postNotebookMessage('initializedMarkdownPreview', {}); break; case 'createMarkdownPreview': createMarkdownPreview(event.data.id, event.data.content, event.data.top); @@ -524,9 +502,7 @@ function webviewPreloads() { resizeObserve(outputNode, outputId, true); - vscode.postMessage({ - __vscode_notebook_message: true, - type: 'dimension', + postNotebookMessage('dimension', { id: outputId, init: true, data: { @@ -602,9 +578,7 @@ function webviewPreloads() { output.parentElement!.style.display = 'block'; output.style.top = top + 'px'; - vscode.postMessage({ - __vscode_notebook_message: true, - type: 'dimension', + postNotebookMessage('dimension', { id: outputId, data: { height: output.clientHeight @@ -674,15 +648,12 @@ function webviewPreloads() { e.preventDefault(); const { cellId } = JSON.parse(data); - const msg: ICellDragEndMessage = { - __vscode_notebook_message: true, - type: 'cell-drag-end', + postNotebookMessage('cell-drag-end', { cellId: cellId, ctrlKey: e.ctrlKey, altKey: e.altKey, position: { clientX: e.clientX, clientY: e.clientY }, - }; - vscode.postMessage(msg); + }); }); function createMarkdownPreview(cellId: string, content: string, top: number) { @@ -702,34 +673,19 @@ function webviewPreloads() { previewContainerNode.classList.add('preview'); previewContainerNode.addEventListener('dblclick', () => { - vscode.postMessage({ - __vscode_notebook_message: true, - type: 'toggleMarkdownPreview', - cellId, - }); + postNotebookMessage('toggleMarkdownPreview', { cellId }); }); previewContainerNode.addEventListener('click', () => { - vscode.postMessage({ - __vscode_notebook_message: true, - type: 'focusMarkdownPreview', - cellId, - }); + postNotebookMessage('focusMarkdownPreview', { cellId }); }); previewContainerNode.addEventListener('mouseenter', () => { - vscode.postMessage({ - __vscode_notebook_message: true, - type: 'mouseEnterMarkdownPreview', - cellId, - }); + postNotebookMessage('mouseEnterMarkdownPreview', { cellId }); }); + previewContainerNode.addEventListener('mouseleave', () => { - vscode.postMessage({ - __vscode_notebook_message: true, - type: 'mouseLeaveMarkdownPreview', - cellId, - }); + postNotebookMessage('mouseLeaveMarkdownPreview', { cellId }); }); previewContainerNode.setAttribute('draggable', 'true'); @@ -742,23 +698,17 @@ function webviewPreloads() { (e.target as HTMLElement).classList.add('dragging'); - const msg: ICellDragStartMessage = { - __vscode_notebook_message: true, - type: 'cell-drag-start', + postNotebookMessage('cell-drag-start', { cellId: cellId, position: { clientX: e.clientX, clientY: e.clientY }, - }; - vscode.postMessage(msg); + }); }); previewContainerNode.addEventListener('drag', e => { - const msg: ICellDragMessage = { - __vscode_notebook_message: true, - type: 'cell-drag', + postNotebookMessage('cell-drag', { cellId: cellId, position: { clientX: e.clientX, clientY: e.clientY }, - }; - vscode.postMessage(msg); + }); }); previewContainerNode.addEventListener('dragend', e => { @@ -778,13 +728,11 @@ function webviewPreloads() { resizeObserve(previewContainerNode, `${cellId}_preview`, false); - vscode.postMessage({ - __vscode_notebook_message: true, - type: 'dimension', + postNotebookMessage('dimension', { id: `${cellId}_preview`, init: true, data: { - height: previewContainerNode.clientHeight + height: previewContainerNode.clientHeight, }, isOutput: false }); @@ -793,6 +741,17 @@ function webviewPreloads() { } } + function postNotebookMessage( + type: T['type'], + properties: Omit + ) { + vscode.postMessage({ + __vscode_notebook_message: true, + type, + ...properties + }); + } + function updateMarkdownPreview(cellId: string, content: string) { const previewNode = document.getElementById(`${cellId}_preview`); if (previewNode) { From 4228908660038d2ee298bb346e2af080b6aae4b6 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Wed, 17 Feb 2021 21:43:03 -0800 Subject: [PATCH 296/325] Fix loading spin icon (fixes #116898) --- src/vs/base/browser/ui/codicons/codicon/codicon-modifiers.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/base/browser/ui/codicons/codicon/codicon-modifiers.css b/src/vs/base/browser/ui/codicons/codicon/codicon-modifiers.css index bae18d887f4..4b5b5141489 100644 --- a/src/vs/base/browser/ui/codicons/codicon/codicon-modifiers.css +++ b/src/vs/base/browser/ui/codicons/codicon/codicon-modifiers.css @@ -13,7 +13,7 @@ } } -.codicon-sync.codicon-modifier-spin, .codicon-loading.codicon-modifier-spin .codicon-gear.codicon-modifier-spin { +.codicon-sync.codicon-modifier-spin, .codicon-loading.codicon-modifier-spin, .codicon-gear.codicon-modifier-spin { /* Use steps to throttle FPS to reduce CPU usage */ animation: codicon-spin 1.5s steps(30) infinite; } From ba8d76eb9710bc727c5f0f896ab969c787997a49 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Wed, 17 Feb 2021 22:50:35 -0800 Subject: [PATCH 297/325] Improve notebook toolbar overlap of markdown cells (fixes #114730) --- src/vs/workbench/contrib/notebook/browser/constants.ts | 6 +++--- .../workbench/contrib/notebook/browser/media/notebook.css | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/constants.ts b/src/vs/workbench/contrib/notebook/browser/constants.ts index ab61c29ec14..f1121eaea24 100644 --- a/src/vs/workbench/contrib/notebook/browser/constants.ts +++ b/src/vs/workbench/contrib/notebook/browser/constants.ts @@ -14,12 +14,12 @@ export const CODE_CELL_LEFT_MARGIN = 32; export const EDITOR_TOOLBAR_HEIGHT = 0; export const BOTTOM_CELL_TOOLBAR_GAP = 16; -export const BOTTOM_CELL_TOOLBAR_HEIGHT = 24; +export const BOTTOM_CELL_TOOLBAR_HEIGHT = 20; export const CELL_STATUSBAR_HEIGHT = 22; // Margin above editor -export const CELL_TOP_MARGIN = 6; -export const CELL_BOTTOM_MARGIN = 6; +export const CELL_TOP_MARGIN = 10; +export const CELL_BOTTOM_MARGIN = 10; // Top and bottom padding inside the monaco editor in a cell, which are included in `cell.editorHeight` // export const EDITOR_TOP_PADDING = 12; diff --git a/src/vs/workbench/contrib/notebook/browser/media/notebook.css b/src/vs/workbench/contrib/notebook/browser/media/notebook.css index 6a72e8e9ae1..424086d7b19 100644 --- a/src/vs/workbench/contrib/notebook/browser/media/notebook.css +++ b/src/vs/workbench/contrib/notebook/browser/media/notebook.css @@ -340,7 +340,7 @@ display: inline-flex; position: absolute; height: 26px; - top: -12px; + top: -14px; /* this lines up the bottom toolbar border with the current line when on line 01 */ z-index: 30; } @@ -646,7 +646,7 @@ .monaco-workbench .notebookOverlay .cell-list-top-cell-toolbar-container .monaco-toolbar, .monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container .monaco-toolbar { - margin: 0px 8px; + margin: -8px 0px 8px; } .monaco-workbench .notebookOverlay .cell-list-top-cell-toolbar-container .monaco-toolbar .action-item, @@ -832,7 +832,7 @@ width: 20px; position: absolute; - top: 6px; + top: 10px; left: 8px; display: flex; justify-content: center; From 63cbe73b2f5d363326c4bea74457edd07dc8bd63 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 18 Feb 2021 07:51:46 +0100 Subject: [PATCH 298/325] chore - consistent imports --- .../browser/actions/developerActions.ts | 24 +- .../workbench/browser/actions/helpActions.ts | 36 +-- .../browser/actions/layoutActions.ts | 102 +++---- .../browser/actions/navigationActions.ts | 14 +- .../browser/actions/windowActions.ts | 50 ++-- .../browser/actions/workspaceActions.ts | 36 +-- .../browser/actions/workspaceCommands.ts | 16 +- .../workbench/browser/parts/compositeBar.ts | 8 +- .../browser/parts/compositeBarActions.ts | 54 ++-- .../workbench/browser/parts/compositePart.ts | 12 +- .../browser/parts/dialogs/dialogHandler.ts | 10 +- .../browser/parts/editor/binaryDiffEditor.ts | 4 +- .../browser/parts/editor/binaryEditor.ts | 10 +- .../parts/editor/editor.contribution.ts | 251 +++++++++--------- .../browser/parts/editor/editorActions.ts | 178 ++++++------- .../browser/parts/editor/editorCommands.ts | 12 +- .../browser/parts/editor/sideBySideEditor.ts | 18 +- .../browser/parts/editor/textDiffEditor.ts | 8 +- .../parts/editor/textResourceEditor.ts | 4 +- .../browser/parts/panel/panelActions.ts | 34 +-- .../browser/parts/sidebar/sidebarPart.ts | 4 +- .../browser/parts/statusbar/statusbarPart.ts | 6 +- .../browser/parts/titlebar/menubarControl.ts | 56 ++-- src/vs/workbench/browser/style.ts | 1 - .../browser/workbench.contribution.ts | 246 ++++++++--------- src/vs/workbench/browser/workbench.ts | 1 - src/vs/workbench/common/resources.ts | 10 +- src/vs/workbench/common/theme.ts | 208 +++++++-------- .../electron-sandbox/actions/windowActions.ts | 24 +- .../parts/dialogs/dialogHandler.ts | 12 +- .../parts/titlebar/titlebarPart.ts | 40 +-- .../services/editor/browser/editorService.ts | 4 +- .../common/notificationService.ts | 6 +- .../textfile/browser/textFileService.ts | 10 +- .../textfile/common/textFileEditorModel.ts | 4 +- .../abstractWorkspaceEditingService.ts | 12 +- 36 files changed, 764 insertions(+), 761 deletions(-) diff --git a/src/vs/workbench/browser/actions/developerActions.ts b/src/vs/workbench/browser/actions/developerActions.ts index 9eb0d3ea714..94160516029 100644 --- a/src/vs/workbench/browser/actions/developerActions.ts +++ b/src/vs/workbench/browser/actions/developerActions.ts @@ -5,7 +5,7 @@ import 'vs/css!./media/actions'; -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { domEvent } from 'vs/base/browser/event'; import { Color } from 'vs/base/common/color'; @@ -34,7 +34,7 @@ class InspectContextKeysAction extends Action2 { constructor() { super({ id: 'workbench.action.inspectContextKeys', - title: { value: nls.localize('inspect context keys', "Inspect Context Keys"), original: 'Inspect Context Keys' }, + title: { value: localize('inspect context keys', "Inspect Context Keys"), original: 'Inspect Context Keys' }, category: CATEGORIES.Developer, f1: true }); @@ -96,7 +96,7 @@ class ToggleScreencastModeAction extends Action2 { constructor() { super({ id: 'workbench.action.toggleScreencastMode', - title: { value: nls.localize('toggle screencast mode', "Toggle Screencast Mode"), original: 'Toggle Screencast Mode' }, + title: { value: localize('toggle screencast mode', "Toggle Screencast Mode"), original: 'Toggle Screencast Mode' }, category: CATEGORIES.Developer, f1: true }); @@ -241,7 +241,7 @@ class LogStorageAction extends Action2 { constructor() { super({ id: 'workbench.action.logStorage', - title: { value: nls.localize({ key: 'logStorage', comment: ['A developer only action to log the contents of the storage for the current window.'] }, "Log Storage Database Contents"), original: 'Log Storage Database Contents' }, + title: { value: localize({ key: 'logStorage', comment: ['A developer only action to log the contents of the storage for the current window.'] }, "Log Storage Database Contents"), original: 'Log Storage Database Contents' }, category: CATEGORIES.Developer, f1: true }); @@ -257,7 +257,7 @@ class LogWorkingCopiesAction extends Action2 { constructor() { super({ id: 'workbench.action.logWorkingCopies', - title: { value: nls.localize({ key: 'logWorkingCopies', comment: ['A developer only action to log the working copies that exist.'] }, "Log Working Copies"), original: 'Log Working Copies' }, + title: { value: localize({ key: 'logWorkingCopies', comment: ['A developer only action to log the working copies that exist.'] }, "Log Working Copies"), original: 'Log Working Copies' }, category: CATEGORIES.Developer, f1: true }); @@ -291,7 +291,7 @@ const configurationRegistry = Registry.as(ConfigurationE configurationRegistry.registerConfiguration({ id: 'screencastMode', order: 9, - title: nls.localize('screencastModeConfigurationTitle', "Screencast Mode"), + title: localize('screencastModeConfigurationTitle', "Screencast Mode"), type: 'object', properties: { 'screencastMode.verticalOffset': { @@ -299,18 +299,18 @@ configurationRegistry.registerConfiguration({ default: 20, minimum: 0, 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.") + description: 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.") + description: 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."), + description: localize('screencastMode.onlyKeyboardShortcuts', "Only show keyboard shortcuts in screencast mode."), default: false }, 'screencastMode.keyboardOverlayTimeout': { @@ -318,20 +318,20 @@ configurationRegistry.registerConfiguration({ default: 800, minimum: 500, maximum: 5000, - description: nls.localize('screencastMode.keyboardOverlayTimeout', "Controls how long (in milliseconds) the keyboard overlay is shown in screencast mode.") + description: localize('screencastMode.keyboardOverlayTimeout', "Controls how long (in milliseconds) the keyboard overlay is shown in screencast mode.") }, 'screencastMode.mouseIndicatorColor': { type: 'string', format: 'color-hex', default: '#FF0000', - description: nls.localize('screencastMode.mouseIndicatorColor', "Controls the color in hex (#RGB, #RGBA, #RRGGBB or #RRGGBBAA) of the mouse indicator in screencast mode.") + description: localize('screencastMode.mouseIndicatorColor', "Controls the color in hex (#RGB, #RGBA, #RRGGBB or #RRGGBBAA) of the mouse indicator in screencast mode.") }, 'screencastMode.mouseIndicatorSize': { type: 'number', default: 20, minimum: 20, maximum: 100, - description: nls.localize('screencastMode.mouseIndicatorSize', "Controls the size (in pixels) of the mouse indicator in screencast mode.") + description: localize('screencastMode.mouseIndicatorSize', "Controls the size (in pixels) of the mouse indicator in screencast mode.") }, } }); diff --git a/src/vs/workbench/browser/actions/helpActions.ts b/src/vs/workbench/browser/actions/helpActions.ts index e12b61219f2..fccf6072614 100644 --- a/src/vs/workbench/browser/actions/helpActions.ts +++ b/src/vs/workbench/browser/actions/helpActions.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import product from 'vs/platform/product/common/product'; import { isMacintosh, isLinux, language } from 'vs/base/common/platform'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -24,7 +24,7 @@ class KeybindingsReferenceAction extends Action2 { constructor() { super({ id: KeybindingsReferenceAction.ID, - title: { value: nls.localize('keybindingsReference', "Keyboard Shortcuts Reference"), original: 'Keyboard Shortcuts Reference' }, + title: { value: localize('keybindingsReference', "Keyboard Shortcuts Reference"), original: 'Keyboard Shortcuts Reference' }, category: CATEGORIES.Help, f1: true, keybinding: { @@ -54,7 +54,7 @@ class OpenDocumentationUrlAction extends Action2 { constructor() { super({ id: OpenDocumentationUrlAction.ID, - title: { value: nls.localize('openDocumentationUrl', "Documentation"), original: 'Documentation' }, + title: { value: localize('openDocumentationUrl', "Documentation"), original: 'Documentation' }, category: CATEGORIES.Help, f1: true }); @@ -78,7 +78,7 @@ class OpenIntroductoryVideosUrlAction extends Action2 { constructor() { super({ id: OpenIntroductoryVideosUrlAction.ID, - title: { value: nls.localize('openIntroductoryVideosUrl', "Introductory Videos"), original: 'Introductory Videos' }, + title: { value: localize('openIntroductoryVideosUrl', "Introductory Videos"), original: 'Introductory Videos' }, category: CATEGORIES.Help, f1: true }); @@ -102,7 +102,7 @@ class OpenTipsAndTricksUrlAction extends Action2 { constructor() { super({ id: OpenTipsAndTricksUrlAction.ID, - title: { value: nls.localize('openTipsAndTricksUrl', "Tips and Tricks"), original: 'Tips and Tricks' }, + title: { value: localize('openTipsAndTricksUrl', "Tips and Tricks"), original: 'Tips and Tricks' }, category: CATEGORIES.Help, f1: true }); @@ -126,7 +126,7 @@ class OpenNewsletterSignupUrlAction extends Action2 { constructor() { super({ id: OpenNewsletterSignupUrlAction.ID, - title: { value: nls.localize('newsletterSignup', "Signup for the VS Code Newsletter"), original: 'Signup for the VS Code Newsletter' }, + title: { value: localize('newsletterSignup', "Signup for the VS Code Newsletter"), original: 'Signup for the VS Code Newsletter' }, category: CATEGORIES.Help, f1: true }); @@ -151,7 +151,7 @@ class OpenTwitterUrlAction extends Action2 { constructor() { super({ id: OpenTwitterUrlAction.ID, - title: { value: nls.localize('openTwitterUrl', "Join Us on Twitter"), original: 'Join Us on Twitter' }, + title: { value: localize('openTwitterUrl', "Join Us on Twitter"), original: 'Join Us on Twitter' }, category: CATEGORIES.Help, f1: true }); @@ -175,7 +175,7 @@ class OpenRequestFeatureUrlAction extends Action2 { constructor() { super({ id: OpenRequestFeatureUrlAction.ID, - title: { value: nls.localize('openUserVoiceUrl', "Search Feature Requests"), original: 'Search Feature Requests' }, + title: { value: localize('openUserVoiceUrl', "Search Feature Requests"), original: 'Search Feature Requests' }, category: CATEGORIES.Help, f1: true }); @@ -199,7 +199,7 @@ class OpenLicenseUrlAction extends Action2 { constructor() { super({ id: OpenLicenseUrlAction.ID, - title: { value: nls.localize('openLicenseUrl', "View License"), original: 'View License' }, + title: { value: localize('openLicenseUrl', "View License"), original: 'View License' }, category: CATEGORIES.Help, f1: true }); @@ -228,7 +228,7 @@ class OpenPrivacyStatementUrlAction extends Action2 { constructor() { super({ id: OpenPrivacyStatementUrlAction.ID, - title: { value: nls.localize('openPrivacyStatement', "Privacy Statement"), original: 'Privacy Statement' }, + title: { value: localize('openPrivacyStatement', "Privacy Statement"), original: 'Privacy Statement' }, category: CATEGORIES.Help, f1: true }); @@ -296,7 +296,7 @@ if (OpenDocumentationUrlAction.AVAILABLE) { group: '1_welcome', command: { id: OpenDocumentationUrlAction.ID, - title: nls.localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation") + title: localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation") }, order: 3 }); @@ -308,7 +308,7 @@ if (KeybindingsReferenceAction.AVAILABLE) { group: '2_reference', command: { id: KeybindingsReferenceAction.ID, - title: nls.localize({ key: 'miKeyboardShortcuts', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts Reference") + title: localize({ key: 'miKeyboardShortcuts', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts Reference") }, order: 1 }); @@ -319,7 +319,7 @@ if (OpenIntroductoryVideosUrlAction.AVAILABLE) { group: '2_reference', command: { id: OpenIntroductoryVideosUrlAction.ID, - title: nls.localize({ key: 'miIntroductoryVideos', comment: ['&& denotes a mnemonic'] }, "Introductory &&Videos") + title: localize({ key: 'miIntroductoryVideos', comment: ['&& denotes a mnemonic'] }, "Introductory &&Videos") }, order: 2 }); @@ -330,7 +330,7 @@ if (OpenTipsAndTricksUrlAction.AVAILABLE) { group: '2_reference', command: { id: OpenTipsAndTricksUrlAction.ID, - title: nls.localize({ key: 'miTipsAndTricks', comment: ['&& denotes a mnemonic'] }, "Tips and Tri&&cks") + title: localize({ key: 'miTipsAndTricks', comment: ['&& denotes a mnemonic'] }, "Tips and Tri&&cks") }, order: 3 }); @@ -342,7 +342,7 @@ if (OpenTwitterUrlAction.AVAILABLE) { group: '3_feedback', command: { id: OpenTwitterUrlAction.ID, - title: nls.localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join Us on Twitter") + title: localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join Us on Twitter") }, order: 1 }); @@ -353,7 +353,7 @@ if (OpenRequestFeatureUrlAction.AVAILABLE) { group: '3_feedback', command: { id: OpenRequestFeatureUrlAction.ID, - title: nls.localize({ key: 'miUserVoice', comment: ['&& denotes a mnemonic'] }, "&&Search Feature Requests") + title: localize({ key: 'miUserVoice', comment: ['&& denotes a mnemonic'] }, "&&Search Feature Requests") }, order: 2 }); @@ -365,7 +365,7 @@ if (OpenLicenseUrlAction.AVAILABLE) { group: '4_legal', command: { id: OpenLicenseUrlAction.ID, - title: nls.localize({ key: 'miLicense', comment: ['&& denotes a mnemonic'] }, "View &&License") + title: localize({ key: 'miLicense', comment: ['&& denotes a mnemonic'] }, "View &&License") }, order: 1 }); @@ -376,7 +376,7 @@ if (OpenPrivacyStatementUrlAction.AVAILABE) { group: '4_legal', command: { id: OpenPrivacyStatementUrlAction.ID, - title: nls.localize({ key: 'miPrivacyStatement', comment: ['&& denotes a mnemonic'] }, "Privac&&y Statement") + title: localize({ key: 'miPrivacyStatement', comment: ['&& denotes a mnemonic'] }, "Privac&&y Statement") }, order: 2 }); diff --git a/src/vs/workbench/browser/actions/layoutActions.ts b/src/vs/workbench/browser/actions/layoutActions.ts index 9bb28af606c..2f3c7c31c6a 100644 --- a/src/vs/workbench/browser/actions/layoutActions.ts +++ b/src/vs/workbench/browser/actions/layoutActions.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; import { Action } from 'vs/base/common/actions'; import { SyncActionDescriptor, MenuId, MenuRegistry, registerAction2, Action2 } from 'vs/platform/actions/common/actions'; @@ -33,7 +33,7 @@ class CloseSidebarAction extends Action2 { constructor() { super({ id: 'workbench.action.closeSidebar', - title: { value: nls.localize('closeSidebar', "Close Side Bar"), original: 'Close Side Bar' }, + title: { value: localize('closeSidebar', "Close Side Bar"), original: 'Close Side Bar' }, category: CATEGORIES.View, f1: true }); @@ -51,7 +51,7 @@ registerAction2(CloseSidebarAction); export class ToggleActivityBarVisibilityAction extends Action2 { static readonly ID = 'workbench.action.toggleActivityBarVisibility'; - static readonly LABEL = nls.localize('toggleActivityBar', "Toggle Activity Bar Visibility"); + static readonly LABEL = localize('toggleActivityBar', "Toggle Activity Bar Visibility"); private static readonly activityBarVisibleKey = 'workbench.activityBar.visible'; @@ -81,7 +81,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '2_workbench_layout', command: { id: ToggleActivityBarVisibilityAction.ID, - title: nls.localize({ key: 'miShowActivityBar', comment: ['&& denotes a mnemonic'] }, "Show &&Activity Bar"), + title: localize({ key: 'miShowActivityBar', comment: ['&& denotes a mnemonic'] }, "Show &&Activity Bar"), toggled: ContextKeyExpr.equals('config.workbench.activityBar.visible', true) }, order: 4 @@ -96,7 +96,7 @@ class ToggleCenteredLayout extends Action2 { constructor() { super({ id: ToggleCenteredLayout.ID, - title: { value: nls.localize('toggleCenteredLayout', "Toggle Centered Layout"), original: 'Toggle Centered Layout' }, + title: { value: localize('toggleCenteredLayout', "Toggle Centered Layout"), original: 'Toggle Centered Layout' }, category: CATEGORIES.View, f1: true }); @@ -115,7 +115,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '1_toggle_view', command: { id: ToggleCenteredLayout.ID, - title: nls.localize({ key: 'miToggleCenteredLayout', comment: ['&& denotes a mnemonic'] }, "&&Centered Layout"), + title: localize({ key: 'miToggleCenteredLayout', comment: ['&& denotes a mnemonic'] }, "&&Centered Layout"), toggled: IsCenteredLayoutContext }, order: 3 @@ -126,7 +126,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { export class ToggleSidebarPositionAction extends Action { static readonly ID = 'workbench.action.toggleSidebarPosition'; - static readonly LABEL = nls.localize('toggleSidebarPosition', "Toggle Side Bar Position"); + static readonly LABEL = localize('toggleSidebarPosition', "Toggle Side Bar Position"); private static readonly sidebarPositionConfigurationKey = 'workbench.sideBar.location'; @@ -147,7 +147,7 @@ export class ToggleSidebarPositionAction extends Action { } static getLabel(layoutService: IWorkbenchLayoutService): string { - return layoutService.getSideBarPosition() === Position.LEFT ? nls.localize('moveSidebarRight', "Move Side Bar Right") : nls.localize('moveSidebarLeft', "Move Side Bar Left"); + return layoutService.getSideBarPosition() === Position.LEFT ? localize('moveSidebarRight', "Move Side Bar Right") : localize('moveSidebarLeft', "Move Side Bar Left"); } } @@ -155,7 +155,7 @@ registerAction2(class extends Action2 { constructor() { super({ id: ToggleSidebarPositionAction.ID, - title: { value: nls.localize('toggleSidebarPosition', "Toggle Side Bar Position"), original: 'Toggle Side Bar Position' }, + title: { value: localize('toggleSidebarPosition', "Toggle Side Bar Position"), original: 'Toggle Side Bar Position' }, category: CATEGORIES.View, f1: true }); @@ -170,7 +170,7 @@ MenuRegistry.appendMenuItems([{ group: '3_workbench_layout_move', command: { id: ToggleSidebarPositionAction.ID, - title: nls.localize('move sidebar right', "Move Side Bar Right") + title: localize('move sidebar right', "Move Side Bar Right") }, when: ContextKeyExpr.and(ContextKeyExpr.notEquals('config.workbench.sideBar.location', 'right'), ContextKeyExpr.equals('viewContainerLocation', ViewContainerLocationToString(ViewContainerLocation.Sidebar))), order: 1 @@ -181,7 +181,7 @@ MenuRegistry.appendMenuItems([{ group: '3_workbench_layout_move', command: { id: ToggleSidebarPositionAction.ID, - title: nls.localize('move sidebar right', "Move Side Bar Right") + title: localize('move sidebar right', "Move Side Bar Right") }, when: ContextKeyExpr.and(ContextKeyExpr.notEquals('config.workbench.sideBar.location', 'right'), ContextKeyExpr.equals('viewLocation', ViewContainerLocationToString(ViewContainerLocation.Sidebar))), order: 1 @@ -192,7 +192,7 @@ MenuRegistry.appendMenuItems([{ group: '3_workbench_layout_move', command: { id: ToggleSidebarPositionAction.ID, - title: nls.localize('move sidebar left', "Move Side Bar Left") + title: localize('move sidebar left', "Move Side Bar Left") }, when: ContextKeyExpr.and(ContextKeyExpr.equals('config.workbench.sideBar.location', 'right'), ContextKeyExpr.equals('viewContainerLocation', ViewContainerLocationToString(ViewContainerLocation.Sidebar))), order: 1 @@ -203,7 +203,7 @@ MenuRegistry.appendMenuItems([{ group: '3_workbench_layout_move', command: { id: ToggleSidebarPositionAction.ID, - title: nls.localize('move sidebar left', "Move Side Bar Left") + title: localize('move sidebar left', "Move Side Bar Left") }, when: ContextKeyExpr.and(ContextKeyExpr.equals('config.workbench.sideBar.location', 'right'), ContextKeyExpr.equals('viewLocation', ViewContainerLocationToString(ViewContainerLocation.Sidebar))), order: 1 @@ -214,7 +214,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '3_workbench_layout_move', command: { id: ToggleSidebarPositionAction.ID, - title: nls.localize({ key: 'miMoveSidebarRight', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Right") + title: localize({ key: 'miMoveSidebarRight', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Right") }, when: ContextKeyExpr.notEquals('config.workbench.sideBar.location', 'right'), order: 2 @@ -224,7 +224,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '3_workbench_layout_move', command: { id: ToggleSidebarPositionAction.ID, - title: nls.localize({ key: 'miMoveSidebarLeft', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Left") + title: localize({ key: 'miMoveSidebarLeft', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Left") }, when: ContextKeyExpr.equals('config.workbench.sideBar.location', 'right'), order: 2 @@ -234,7 +234,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { export class ToggleEditorVisibilityAction extends Action { static readonly ID = 'workbench.action.toggleEditorVisibility'; - static readonly LABEL = nls.localize('toggleEditor', "Toggle Editor Area Visibility"); + static readonly LABEL = localize('toggleEditor', "Toggle Editor Area Visibility"); constructor( id: string, @@ -255,7 +255,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '2_workbench_layout', command: { id: ToggleEditorVisibilityAction.ID, - title: nls.localize({ key: 'miShowEditorArea', comment: ['&& denotes a mnemonic'] }, "Show &&Editor Area"), + title: localize({ key: 'miShowEditorArea', comment: ['&& denotes a mnemonic'] }, "Show &&Editor Area"), toggled: EditorAreaVisibleContext }, order: 5 @@ -263,7 +263,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { group: '2_appearance', - title: nls.localize({ key: 'miAppearance', comment: ['&& denotes a mnemonic'] }, "&&Appearance"), + title: localize({ key: 'miAppearance', comment: ['&& denotes a mnemonic'] }, "&&Appearance"), submenu: MenuId.MenubarAppearanceMenu, order: 1 }); @@ -273,7 +273,7 @@ registerAction2(class extends Action2 { constructor() { super({ id: TOGGLE_SIDEBAR_VISIBILITY_ACTION_ID, - title: { value: nls.localize('toggleSidebar', "Toggle Side Bar Visibility"), original: 'Toggle Side Bar Visibility' }, + title: { value: localize('toggleSidebar', "Toggle Side Bar Visibility"), original: 'Toggle Side Bar Visibility' }, category: CATEGORIES.View, f1: true, keybinding: { @@ -293,7 +293,7 @@ MenuRegistry.appendMenuItems([{ group: '3_workbench_layout_move', command: { id: TOGGLE_SIDEBAR_VISIBILITY_ACTION_ID, - title: nls.localize('compositePart.hideSideBarLabel', "Hide Side Bar"), + title: localize('compositePart.hideSideBarLabel', "Hide Side Bar"), }, when: ContextKeyExpr.and(SideBarVisibleContext, ContextKeyExpr.equals('viewContainerLocation', ViewContainerLocationToString(ViewContainerLocation.Sidebar))), order: 2 @@ -304,7 +304,7 @@ MenuRegistry.appendMenuItems([{ group: '3_workbench_layout_move', command: { id: TOGGLE_SIDEBAR_VISIBILITY_ACTION_ID, - title: nls.localize('compositePart.hideSideBarLabel', "Hide Side Bar"), + title: localize('compositePart.hideSideBarLabel', "Hide Side Bar"), }, when: ContextKeyExpr.and(SideBarVisibleContext, ContextKeyExpr.equals('viewLocation', ViewContainerLocationToString(ViewContainerLocation.Sidebar))), order: 2 @@ -315,7 +315,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '2_workbench_layout', command: { id: TOGGLE_SIDEBAR_VISIBILITY_ACTION_ID, - title: nls.localize({ key: 'miShowSidebar', comment: ['&& denotes a mnemonic'] }, "Show &&Side Bar"), + title: localize({ key: 'miShowSidebar', comment: ['&& denotes a mnemonic'] }, "Show &&Side Bar"), toggled: SideBarVisibleContext }, order: 1 @@ -326,7 +326,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { export class ToggleStatusbarVisibilityAction extends Action { static readonly ID = 'workbench.action.toggleStatusbarVisibility'; - static readonly LABEL = nls.localize('toggleStatusbar', "Toggle Status Bar Visibility"); + static readonly LABEL = localize('toggleStatusbar', "Toggle Status Bar Visibility"); private static readonly statusbarVisibleKey = 'workbench.statusBar.visible'; @@ -353,7 +353,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '2_workbench_layout', command: { id: ToggleStatusbarVisibilityAction.ID, - title: nls.localize({ key: 'miShowStatusbar', comment: ['&& denotes a mnemonic'] }, "Show S&&tatus Bar"), + title: localize({ key: 'miShowStatusbar', comment: ['&& denotes a mnemonic'] }, "Show S&&tatus Bar"), toggled: ContextKeyExpr.equals('config.workbench.statusBar.visible', true) }, order: 3 @@ -364,7 +364,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { class ToggleTabsVisibilityAction extends Action { static readonly ID = 'workbench.action.toggleTabsVisibility'; - static readonly LABEL = nls.localize('toggleTabs', "Toggle Tab Visibility"); + static readonly LABEL = localize('toggleTabs', "Toggle Tab Visibility"); private static readonly tabsVisibleKey = 'workbench.editor.showTabs'; @@ -395,7 +395,7 @@ registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleTabsVisibilityA class ToggleZenMode extends Action { static readonly ID = 'workbench.action.toggleZenMode'; - static readonly LABEL = nls.localize('toggleZenMode', "Toggle Zen Mode"); + static readonly LABEL = localize('toggleZenMode', "Toggle Zen Mode"); constructor( id: string, @@ -416,7 +416,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '1_toggle_view', command: { id: ToggleZenMode.ID, - title: nls.localize('miToggleZenMode', "Zen Mode"), + title: localize('miToggleZenMode', "Zen Mode"), toggled: InEditorZenModeContext }, order: 2 @@ -438,7 +438,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ export class ToggleMenuBarAction extends Action { static readonly ID = 'workbench.action.toggleMenuBar'; - static readonly LABEL = nls.localize('toggleMenuBar', "Toggle Menu Bar"); + static readonly LABEL = localize('toggleMenuBar', "Toggle Menu Bar"); constructor( id: string, @@ -461,7 +461,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '2_workbench_layout', command: { id: ToggleMenuBarAction.ID, - title: nls.localize({ key: 'miShowMenuBar', comment: ['&& denotes a mnemonic'] }, "Show Menu &&Bar"), + title: localize({ key: 'miShowMenuBar', comment: ['&& denotes a mnemonic'] }, "Show Menu &&Bar"), toggled: ContextKeyExpr.and(IsMacNativeContext.toNegated(), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'hidden'), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'toggle'), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'compact')) }, when: IsMacNativeContext.toNegated(), @@ -472,7 +472,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { export class ResetViewLocationsAction extends Action { static readonly ID = 'workbench.action.resetViewLocations'; - static readonly LABEL = nls.localize('resetViewLocations', "Reset View Locations"); + static readonly LABEL = localize('resetViewLocations', "Reset View Locations"); constructor( id: string, @@ -492,7 +492,7 @@ registry.registerWorkbenchAction(SyncActionDescriptor.from(ResetViewLocationsAct // --- Move View with Command export class MoveViewAction extends Action { static readonly ID = 'workbench.action.moveView'; - static readonly LABEL = nls.localize('moveView', "Move View"); + static readonly LABEL = localize('moveView', "Move View"); constructor( id: string, @@ -521,7 +521,7 @@ export class MoveViewAction extends Action { if (!hasAddedView) { results.push({ type: 'separator', - label: nls.localize('sidebarContainer', "Side Bar / {0}", containerModel.title) + label: localize('sidebarContainer', "Side Bar / {0}", containerModel.title) }); hasAddedView = true; } @@ -545,7 +545,7 @@ export class MoveViewAction extends Action { if (!hasAddedView) { results.push({ type: 'separator', - label: nls.localize('panelContainer', "Panel / {0}", containerModel.title) + label: localize('panelContainer', "Panel / {0}", containerModel.title) }); hasAddedView = true; } @@ -563,7 +563,7 @@ export class MoveViewAction extends Action { private async getView(viewId?: string): Promise { const quickPick = this.quickInputService.createQuickPick(); - quickPick.placeholder = nls.localize('moveFocusedView.selectView', "Select a View to Move"); + quickPick.placeholder = 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[]; @@ -608,7 +608,7 @@ registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveViewAction), 'Vie // --- 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"); + static readonly LABEL = localize('moveFocusedView', "Move Focused View"); constructor( id: string, @@ -628,19 +628,19 @@ export class MoveFocusedViewAction extends Action { 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.")); + this.notificationService.error(localize('moveFocusedView.error.noFocusedView', "There is no view currently focused.")); return; } const viewDescriptor = this.viewDescriptorService.getViewDescriptorById(focusedViewId); if (!viewDescriptor || !viewDescriptor.canMoveView) { - this.notificationService.error(nls.localize('moveFocusedView.error.nonMovableView', "The currently focused view is not movable.")); + this.notificationService.error(localize('moveFocusedView.error.nonMovableView', "The currently focused view is not movable.")); return; } const quickPick = this.quickInputService.createQuickPick(); - quickPick.placeholder = nls.localize('moveFocusedView.selectDestination', "Select a Destination for the View"); - 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); + quickPick.placeholder = localize('moveFocusedView.selectDestination', "Select a Destination for the View"); + quickPick.title = 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 = []; const currentContainer = this.viewDescriptorService.getViewContainerByViewId(focusedViewId)!; @@ -650,20 +650,20 @@ export class MoveFocusedViewAction extends Action { if (!(isViewSolo && currentLocation === ViewContainerLocation.Panel)) { items.push({ id: '_.panel.newcontainer', - label: nls.localize({ key: 'moveFocusedView.newContainerInPanel', comment: ['Creates a new top-level tab in the panel.'] }, "New Panel Entry"), + label: localize({ key: 'moveFocusedView.newContainerInPanel', comment: ['Creates a new top-level tab in the panel.'] }, "New Panel Entry"), }); } if (!(isViewSolo && currentLocation === ViewContainerLocation.Sidebar)) { items.push({ id: '_.sidebar.newcontainer', - label: nls.localize('moveFocusedView.newContainerInSidebar', "New Side Bar Entry") + label: localize('moveFocusedView.newContainerInSidebar', "New Side Bar Entry") }); } items.push({ type: 'separator', - label: nls.localize('sidebar', "Side Bar") + label: localize('sidebar', "Side Bar") }); const pinnedViewlets = this.activityBarService.getVisibleViewContainerIds(); @@ -684,7 +684,7 @@ export class MoveFocusedViewAction extends Action { items.push({ type: 'separator', - label: nls.localize('panel', "Panel") + label: localize('panel', "Panel") }); const pinnedPanels = this.panelService.getPinnedPanels(); @@ -731,7 +731,7 @@ registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveFocusedViewAction // --- Reset View Location with Command export class ResetFocusedViewLocationAction extends Action { static readonly ID = 'workbench.action.resetFocusedViewLocation'; - static readonly LABEL = nls.localize('resetFocusedViewLocation', "Reset Focused View Location"); + static readonly LABEL = localize('resetFocusedViewLocation', "Reset Focused View Location"); constructor( id: string, @@ -753,7 +753,7 @@ export class ResetFocusedViewLocationAction extends Action { } if (!viewDescriptor) { - this.notificationService.error(nls.localize('resetFocusedView.error.noFocusedView', "There is no view currently focused.")); + this.notificationService.error(localize('resetFocusedView.error.noFocusedView', "There is no view currently focused.")); return; } @@ -807,7 +807,7 @@ export class IncreaseViewSizeAction extends BaseResizeViewAction { constructor() { super({ id: 'workbench.action.increaseViewSize', - title: { value: nls.localize('increaseViewSize', "Increase Current View Size"), original: 'Increase Current View Size' }, + title: { value: localize('increaseViewSize', "Increase Current View Size"), original: 'Increase Current View Size' }, f1: true }); } @@ -822,7 +822,7 @@ export class IncreaseViewWidthAction extends BaseResizeViewAction { constructor() { super({ id: 'workbench.action.increaseViewWidth', - title: { value: nls.localize('increaseEditorWidth', "Increase Editor Width"), original: 'Increase Editor Width' }, + title: { value: localize('increaseEditorWidth', "Increase Editor Width"), original: 'Increase Editor Width' }, f1: true }); } @@ -837,7 +837,7 @@ export class IncreaseViewHeightAction extends BaseResizeViewAction { constructor() { super({ id: 'workbench.action.increaseViewHeight', - title: { value: nls.localize('increaseEditorHeight', "Increase Editor Height"), original: 'Increase Editor Height' }, + title: { value: localize('increaseEditorHeight', "Increase Editor Height"), original: 'Increase Editor Height' }, f1: true }); } @@ -851,7 +851,7 @@ export class DecreaseViewSizeAction extends BaseResizeViewAction { constructor() { super({ id: 'workbench.action.decreaseViewSize', - title: { value: nls.localize('decreaseViewSize', "Decrease Current View Size"), original: 'Decrease Current View Size' }, + title: { value: localize('decreaseViewSize', "Decrease Current View Size"), original: 'Decrease Current View Size' }, f1: true }); } @@ -865,7 +865,7 @@ export class DecreaseViewWidthAction extends BaseResizeViewAction { constructor() { super({ id: 'workbench.action.decreaseViewWidth', - title: { value: nls.localize('decreaseEditorWidth', "Decrease Editor Width"), original: 'Decrease Editor Width' }, + title: { value: localize('decreaseEditorWidth', "Decrease Editor Width"), original: 'Decrease Editor Width' }, f1: true }); } @@ -881,7 +881,7 @@ export class DecreaseViewHeightAction extends BaseResizeViewAction { constructor() { super({ id: 'workbench.action.decreaseViewHeight', - title: { value: nls.localize('decreaseEditorHeight', "Decrease Editor Height"), original: 'Decrease Editor Height' }, + title: { value: localize('decreaseEditorHeight', "Decrease Editor Height"), original: 'Decrease Editor Height' }, f1: true }); } diff --git a/src/vs/workbench/browser/actions/navigationActions.ts b/src/vs/workbench/browser/actions/navigationActions.ts index 01831676a97..6122d65d983 100644 --- a/src/vs/workbench/browser/actions/navigationActions.ts +++ b/src/vs/workbench/browser/actions/navigationActions.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; import { Action } from 'vs/base/common/actions'; import { IEditorGroupsService, GroupDirection, GroupLocation, IFindGroupScope } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -137,7 +137,7 @@ abstract class BaseNavigationAction extends Action { class NavigateLeftAction extends BaseNavigationAction { static readonly ID = 'workbench.action.navigateLeft'; - static readonly LABEL = nls.localize('navigateLeft', "Navigate to the View on the Left"); + static readonly LABEL = localize('navigateLeft', "Navigate to the View on the Left"); constructor( id: string, @@ -154,7 +154,7 @@ class NavigateLeftAction extends BaseNavigationAction { class NavigateRightAction extends BaseNavigationAction { static readonly ID = 'workbench.action.navigateRight'; - static readonly LABEL = nls.localize('navigateRight', "Navigate to the View on the Right"); + static readonly LABEL = localize('navigateRight', "Navigate to the View on the Right"); constructor( id: string, @@ -171,7 +171,7 @@ class NavigateRightAction extends BaseNavigationAction { class NavigateUpAction extends BaseNavigationAction { static readonly ID = 'workbench.action.navigateUp'; - static readonly LABEL = nls.localize('navigateUp', "Navigate to the View Above"); + static readonly LABEL = localize('navigateUp', "Navigate to the View Above"); constructor( id: string, @@ -188,7 +188,7 @@ class NavigateUpAction extends BaseNavigationAction { class NavigateDownAction extends BaseNavigationAction { static readonly ID = 'workbench.action.navigateDown'; - static readonly LABEL = nls.localize('navigateDown', "Navigate to the View Below"); + static readonly LABEL = localize('navigateDown', "Navigate to the View Below"); constructor( id: string, @@ -229,7 +229,7 @@ function focusNextOrPreviousPart(layoutService: IWorkbenchLayoutService, editorS export class FocusNextPart extends Action { static readonly ID = 'workbench.action.focusNextPart'; - static readonly LABEL = nls.localize('focusNextPart', "Focus Next Part"); + static readonly LABEL = localize('focusNextPart', "Focus Next Part"); constructor( id: string, @@ -247,7 +247,7 @@ export class FocusNextPart extends Action { export class FocusPreviousPart extends Action { static readonly ID = 'workbench.action.focusPreviousPart'; - static readonly LABEL = nls.localize('focusPreviousPart', "Focus Previous Part"); + static readonly LABEL = localize('focusPreviousPart', "Focus Previous Part"); constructor( id: string, diff --git a/src/vs/workbench/browser/actions/windowActions.ts b/src/vs/workbench/browser/actions/windowActions.ts index 926527871e8..758a5b12d3c 100644 --- a/src/vs/workbench/browser/actions/windowActions.ts +++ b/src/vs/workbench/browser/actions/windowActions.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { Action } from 'vs/base/common/actions'; import { IWindowOpenable } from 'vs/platform/windows/common/windows'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; @@ -46,18 +46,18 @@ abstract class BaseOpenRecentAction extends Action { private readonly removeFromRecentlyOpened: IQuickInputButton = { iconClass: Codicon.removeClose.classNames, - tooltip: nls.localize('remove', "Remove from Recently Opened") + tooltip: localize('remove', "Remove from Recently Opened") }; private readonly dirtyRecentlyOpenedFolder: IQuickInputButton = { iconClass: 'dirty-workspace ' + Codicon.closeDirty.classNames, - tooltip: nls.localize('dirtyRecentlyOpenedFolder', "Folder With Unsaved Files"), + tooltip: localize('dirtyRecentlyOpenedFolder', "Folder With Unsaved Files"), alwaysVisible: true }; private readonly dirtyRecentlyOpenedWorkspace: IQuickInputButton = { ...this.dirtyRecentlyOpenedFolder, - tooltip: nls.localize('dirtyRecentlyOpenedWorkspace', "Workspace With Unsaved Files"), + tooltip: localize('dirtyRecentlyOpenedWorkspace', "Workspace With Unsaved Files"), }; constructor( @@ -133,14 +133,14 @@ abstract class BaseOpenRecentAction extends Action { let keyMods: IKeyMods | undefined; - const workspaceSeparator: IQuickPickSeparator = { type: 'separator', label: hasWorkspaces ? nls.localize('workspacesAndFolders', "folders & workspaces") : nls.localize('folders', "folders") }; - const fileSeparator: IQuickPickSeparator = { type: 'separator', label: nls.localize('files', "files") }; + const workspaceSeparator: IQuickPickSeparator = { type: 'separator', label: hasWorkspaces ? localize('workspacesAndFolders', "folders & workspaces") : localize('folders', "folders") }; + const fileSeparator: IQuickPickSeparator = { type: 'separator', label: localize('files', "files") }; const picks = [workspaceSeparator, ...workspacePicks, fileSeparator, ...filePicks]; const pick = await this.quickInputService.pick(picks, { contextKey: inRecentFilesPickerContextKey, activeItem: [...workspacePicks, ...filePicks][autoFocusSecondEntry ? 1 : 0], - placeHolder: isMacintosh ? nls.localize('openRecentPlaceholderMac', "Select to open (hold Cmd-key to force new window or Alt-key for same window)") : nls.localize('openRecentPlaceholder', "Select to open (hold Ctrl-key to force new window or Alt-key for same window)"), + placeHolder: isMacintosh ? localize('openRecentPlaceholderMac', "Select to open (hold Cmd-key to force new window or Alt-key for same window)") : localize('openRecentPlaceholder', "Select to open (hold Ctrl-key to force new window or Alt-key for same window)"), matchOnDescription: true, onKeyMods: mods => keyMods = mods, quickNavigate: this.isQuickNavigate() ? { keybindings: this.keybindingService.lookupKeybindings(this.id) } : undefined, @@ -157,9 +157,9 @@ abstract class BaseOpenRecentAction extends Action { const isDirtyWorkspace = context.button === this.dirtyRecentlyOpenedWorkspace; const result = await this.dialogService.confirm({ type: 'question', - title: isDirtyWorkspace ? nls.localize('dirtyWorkspace', "Workspace with Unsaved Files") : nls.localize('dirtyFolder', "Folder with Unsaved Files"), - message: isDirtyWorkspace ? nls.localize('dirtyWorkspaceConfirm', "Do you want to open the workspace to review the unsaved files?") : nls.localize('dirtyFolderConfirm', "Do you want to open the folder to review the unsaved files?"), - detail: isDirtyWorkspace ? nls.localize('dirtyWorkspaceConfirmDetail', "Workspaces with unsaved files cannot be removed until all unsaved files have been saved or reverted.") : nls.localize('dirtyFolderConfirmDetail', "Folders with unsaved files cannot be removed until all unsaved files have been saved or reverted.") + title: isDirtyWorkspace ? localize('dirtyWorkspace', "Workspace with Unsaved Files") : localize('dirtyFolder', "Folder with Unsaved Files"), + message: isDirtyWorkspace ? localize('dirtyWorkspaceConfirm', "Do you want to open the workspace to review the unsaved files?") : localize('dirtyFolderConfirm', "Do you want to open the folder to review the unsaved files?"), + detail: isDirtyWorkspace ? localize('dirtyWorkspaceConfirmDetail', "Workspaces with unsaved files cannot be removed until all unsaved files have been saved or reverted.") : localize('dirtyFolderConfirmDetail', "Folders with unsaved files cannot be removed until all unsaved files have been saved or reverted.") }); if (result.confirmed) { @@ -212,7 +212,7 @@ abstract class BaseOpenRecentAction extends Action { return { iconClasses, label: name, - ariaLabel: isDirty ? isWorkspace ? nls.localize('recentDirtyWorkspaceAriaLabel', "{0}, workspace with unsaved changes", name) : nls.localize('recentDirtyFolderAriaLabel', "{0}, folder with unsaved changes", name) : name, + ariaLabel: isDirty ? isWorkspace ? localize('recentDirtyWorkspaceAriaLabel', "{0}, workspace with unsaved changes", name) : localize('recentDirtyFolderAriaLabel', "{0}, folder with unsaved changes", name) : name, description: parentPath, buttons: isDirty ? [isWorkspace ? this.dirtyRecentlyOpenedWorkspace : this.dirtyRecentlyOpenedFolder] : [this.removeFromRecentlyOpened], openable, @@ -224,7 +224,7 @@ abstract class BaseOpenRecentAction extends Action { export class OpenRecentAction extends BaseOpenRecentAction { static readonly ID = 'workbench.action.openRecent'; - static readonly LABEL = nls.localize('openRecent', "Open Recent..."); + static readonly LABEL = localize('openRecent', "Open Recent..."); constructor( id: string, @@ -250,7 +250,7 @@ export class OpenRecentAction extends BaseOpenRecentAction { class QuickPickRecentAction extends BaseOpenRecentAction { static readonly ID = 'workbench.action.quickOpenRecent'; - static readonly LABEL = nls.localize('quickOpenRecent', "Quick Open Recent..."); + static readonly LABEL = localize('quickOpenRecent', "Quick Open Recent..."); constructor( id: string, @@ -276,7 +276,7 @@ class QuickPickRecentAction extends BaseOpenRecentAction { class ToggleFullScreenAction extends Action { static readonly ID = 'workbench.action.toggleFullScreen'; - static readonly LABEL = nls.localize('toggleFullScreen', "Toggle Full Screen"); + static readonly LABEL = localize('toggleFullScreen', "Toggle Full Screen"); constructor( id: string, @@ -294,7 +294,7 @@ class ToggleFullScreenAction extends Action { export class ReloadWindowAction extends Action { static readonly ID = 'workbench.action.reloadWindow'; - static readonly LABEL = nls.localize('reloadWindow', "Reload Window"); + static readonly LABEL = localize('reloadWindow', "Reload Window"); constructor( id: string, @@ -314,7 +314,7 @@ export class ReloadWindowAction extends Action { class ShowAboutDialogAction extends Action { static readonly ID = 'workbench.action.showAboutDialog'; - static readonly LABEL = nls.localize('about', "About"); + static readonly LABEL = localize('about', "About"); constructor( id: string, @@ -332,7 +332,7 @@ class ShowAboutDialogAction extends Action { export class NewWindowAction extends Action { static readonly ID = 'workbench.action.newWindow'; - static readonly LABEL = nls.localize('newWindow', "New Window"); + static readonly LABEL = localize('newWindow', "New Window"); constructor( id: string, @@ -352,7 +352,7 @@ class BlurAction extends Action2 { constructor() { super({ id: 'workbench.action.blur', - title: nls.localize('blur', "Remove keyboard focus from focused element") + title: localize('blur', "Remove keyboard focus from focused element") }); } @@ -369,7 +369,7 @@ const registry = Registry.as(Extensions.WorkbenchActio // --- Actions Registration -const fileCategory = nls.localize('file', "File"); +const fileCategory = localize('file', "File"); registry.registerWorkbenchAction(SyncActionDescriptor.from(NewWindowAction, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_N }), 'New Window'); registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickPickRecentAction), 'File: Quick Open Recent...', fileCategory); registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenRecentAction, { primary: KeyMod.CtrlCmd | KeyCode.KEY_R, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R } }), 'File: Open Recent...', fileCategory); @@ -426,7 +426,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { group: 'z_ConfirmClose', command: { id: 'workbench.action.toggleConfirmBeforeClose', - title: nls.localize('miConfirmClose', "Confirm Before Close"), + title: localize('miConfirmClose', "Confirm Before Close"), toggled: ContextKeyExpr.notEquals('config.window.confirmBeforeClose', 'never') }, order: 1, @@ -437,13 +437,13 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { group: '1_new', command: { id: NewWindowAction.ID, - title: nls.localize({ key: 'miNewWindow', comment: ['&& denotes a mnemonic'] }, "New &&Window") + title: localize({ key: 'miNewWindow', comment: ['&& denotes a mnemonic'] }, "New &&Window") }, order: 2 }); MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - title: nls.localize({ key: 'miOpenRecent', comment: ['&& denotes a mnemonic'] }, "Open &&Recent"), + title: localize({ key: 'miOpenRecent', comment: ['&& denotes a mnemonic'] }, "Open &&Recent"), submenu: MenuId.MenubarRecentMenu, group: '2_open', order: 4 @@ -453,7 +453,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarRecentMenu, { group: 'y_more', command: { id: OpenRecentAction.ID, - title: nls.localize({ key: 'miMore', comment: ['&& denotes a mnemonic'] }, "&&More...") + title: localize({ key: 'miMore', comment: ['&& denotes a mnemonic'] }, "&&More...") }, order: 1 }); @@ -462,7 +462,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '1_toggle_view', command: { id: ToggleFullScreenAction.ID, - title: nls.localize({ key: 'miToggleFullScreen', comment: ['&& denotes a mnemonic'] }, "&&Full Screen"), + title: localize({ key: 'miToggleFullScreen', comment: ['&& denotes a mnemonic'] }, "&&Full Screen"), toggled: IsFullscreenContext }, order: 1 @@ -472,7 +472,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { group: 'z_about', command: { id: ShowAboutDialogAction.ID, - title: nls.localize({ key: 'miAbout', comment: ['&& denotes a mnemonic'] }, "&&About") + title: localize({ key: 'miAbout', comment: ['&& denotes a mnemonic'] }, "&&About") }, order: 1, when: IsMacNativeContext.toNegated() diff --git a/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts index 8817e5fd820..03628a38b89 100644 --- a/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Action } from 'vs/base/common/actions'; -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; @@ -28,7 +28,7 @@ import { WORKSPACE_TRUST_ENABLED } from 'vs/workbench/services/workspaces/common export class OpenFileAction extends Action { static readonly ID = 'workbench.action.files.openFile'; - static readonly LABEL = nls.localize('openFile', "Open File..."); + static readonly LABEL = localize('openFile', "Open File..."); constructor( id: string, @@ -46,7 +46,7 @@ export class OpenFileAction extends Action { export class OpenFolderAction extends Action { static readonly ID = 'workbench.action.files.openFolder'; - static readonly LABEL = nls.localize('openFolder', "Open Folder..."); + static readonly LABEL = localize('openFolder', "Open Folder..."); constructor( id: string, @@ -64,7 +64,7 @@ export class OpenFolderAction extends Action { export class OpenFileFolderAction extends Action { static readonly ID = 'workbench.action.files.openFileFolder'; - static readonly LABEL = nls.localize('openFileFolder', "Open..."); + static readonly LABEL = localize('openFileFolder', "Open..."); constructor( id: string, @@ -82,7 +82,7 @@ export class OpenFileFolderAction extends Action { export class OpenWorkspaceAction extends Action { static readonly ID = 'workbench.action.openWorkspace'; - static readonly LABEL = nls.localize('openWorkspaceAction', "Open Workspace..."); + static readonly LABEL = localize('openWorkspaceAction', "Open Workspace..."); constructor( id: string, @@ -100,7 +100,7 @@ export class OpenWorkspaceAction extends Action { export class CloseWorkspaceAction extends Action { static readonly ID = 'workbench.action.closeFolder'; - static readonly LABEL = nls.localize('closeWorkspace', "Close Workspace"); + static readonly LABEL = localize('closeWorkspace', "Close Workspace"); constructor( id: string, @@ -115,7 +115,7 @@ export class CloseWorkspaceAction extends Action { async run(): Promise { if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { - this.notificationService.info(nls.localize('noWorkspaceOrFolderOpened', "There is currently no workspace or folder opened in this instance to close.")); + this.notificationService.info(localize('noWorkspaceOrFolderOpened', "There is currently no workspace or folder opened in this instance to close.")); return; } @@ -126,7 +126,7 @@ export class CloseWorkspaceAction extends Action { export class OpenWorkspaceConfigFileAction extends Action { static readonly ID = 'workbench.action.openWorkspaceConfigFile'; - static readonly LABEL = nls.localize('openWorkspaceConfigFile', "Open Workspace Configuration File"); + static readonly LABEL = localize('openWorkspaceConfigFile', "Open Workspace Configuration File"); constructor( id: string, @@ -168,7 +168,7 @@ export class AddRootFolderAction extends Action { export class GlobalRemoveRootFolderAction extends Action { static readonly ID = 'workbench.action.removeRootFolder'; - static readonly LABEL = nls.localize('globalRemoveFolderFromWorkspace', "Remove Folder from Workspace..."); + static readonly LABEL = localize('globalRemoveFolderFromWorkspace', "Remove Folder from Workspace..."); constructor( id: string, @@ -196,7 +196,7 @@ export class GlobalRemoveRootFolderAction extends Action { export class SaveWorkspaceAsAction extends Action { static readonly ID = 'workbench.action.saveWorkspaceAs'; - static readonly LABEL = nls.localize('saveWorkspaceAsAction', "Save Workspace As..."); + static readonly LABEL = localize('saveWorkspaceAsAction', "Save Workspace As..."); constructor( id: string, @@ -226,7 +226,7 @@ export class SaveWorkspaceAsAction extends Action { export class DuplicateWorkspaceInNewWindowAction extends Action { static readonly ID = 'workbench.action.duplicateWorkspaceInNewWindow'; - static readonly LABEL = nls.localize('duplicateWorkspaceInNewWindow', "Duplicate As Workspace in New Window"); + static readonly LABEL = localize('duplicateWorkspaceInNewWindow', "Duplicate As Workspace in New Window"); constructor( id: string, @@ -255,9 +255,9 @@ class WorkspaceTrustManageAction extends Action2 { constructor() { super({ id: 'workbench.action.manageTrust', - title: { value: nls.localize('manageTrustAction', "Manage Workspace Trust"), original: 'Manage Workspace Trust' }, + title: { value: localize('manageTrustAction', "Manage Workspace Trust"), original: 'Manage Workspace Trust' }, precondition: ContextKeyExpr.equals(`config.${WORKSPACE_TRUST_ENABLED}`, true), - category: nls.localize('workspacesCategory', "Workspaces"), + category: localize('workspacesCategory', "Workspaces"), f1: true }); } @@ -273,7 +273,7 @@ registerAction2(WorkspaceTrustManageAction); // --- Actions Registration const registry = Registry.as(Extensions.WorkbenchActions); -const workspacesCategory = nls.localize('workspaces', "Workspaces"); +const workspacesCategory = localize('workspaces', "Workspaces"); registry.registerWorkbenchAction(SyncActionDescriptor.from(AddRootFolderAction), 'Workspaces: Add Folder to Workspace...', workspacesCategory); registry.registerWorkbenchAction(SyncActionDescriptor.from(GlobalRemoveRootFolderAction), 'Workspaces: Remove Folder from Workspace...', workspacesCategory); @@ -291,7 +291,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { group: '3_workspace', command: { id: ADD_ROOT_FOLDER_COMMAND_ID, - title: nls.localize({ key: 'miAddFolderToWorkspace', comment: ['&& denotes a mnemonic'] }, "A&&dd Folder to Workspace...") + title: localize({ key: 'miAddFolderToWorkspace', comment: ['&& denotes a mnemonic'] }, "A&&dd Folder to Workspace...") }, order: 1 }); @@ -300,7 +300,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { group: '3_workspace', command: { id: SaveWorkspaceAsAction.ID, - title: nls.localize('miSaveWorkspaceAs', "Save Workspace As...") + title: localize('miSaveWorkspaceAs', "Save Workspace As...") }, order: 2, when: EmptyWorkspaceSupportContext @@ -318,7 +318,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { group: '6_close', command: { id: CloseWorkspaceAction.ID, - title: nls.localize({ key: 'miCloseFolder', comment: ['&& denotes a mnemonic'] }, "Close &&Folder"), + title: localize({ key: 'miCloseFolder', comment: ['&& denotes a mnemonic'] }, "Close &&Folder"), precondition: WorkspaceFolderCountContext.notEqualsTo('0') }, order: 3, @@ -329,7 +329,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { group: '6_close', command: { id: CloseWorkspaceAction.ID, - title: nls.localize({ key: 'miCloseWorkspace', comment: ['&& denotes a mnemonic'] }, "Close &&Workspace") + title: localize({ key: 'miCloseWorkspace', comment: ['&& denotes a mnemonic'] }, "Close &&Workspace") }, order: 3, when: ContextKeyExpr.and(WorkbenchStateContext.isEqualTo('workspace'), EmptyWorkspaceSupportContext) diff --git a/src/vs/workbench/browser/actions/workspaceCommands.ts b/src/vs/workbench/browser/actions/workspaceCommands.ts index 7f43e0fb0e5..2f6b8df6f13 100644 --- a/src/vs/workbench/browser/actions/workspaceCommands.ts +++ b/src/vs/workbench/browser/actions/workspaceCommands.ts @@ -3,10 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; -import * as resources from 'vs/base/common/resources'; +import { dirname, removeTrailingPathSeparator } from 'vs/base/common/resources'; import { CancellationToken } from 'vs/base/common/cancellation'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; @@ -24,7 +24,7 @@ import { IOpenWindowOptions, IWindowOpenable } from 'vs/platform/windows/common/ import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; export const ADD_ROOT_FOLDER_COMMAND_ID = 'addRootFolder'; -export const ADD_ROOT_FOLDER_LABEL = nls.localize('addFolderToWorkspace', "Add Folder to Workspace..."); +export const ADD_ROOT_FOLDER_LABEL = localize('addFolderToWorkspace', "Add Folder to Workspace..."); export const PICK_WORKSPACE_FOLDER_COMMAND_ID = '_workbench.pickWorkspaceFolder'; @@ -61,8 +61,8 @@ CommandsRegistry.registerCommand({ const workspaceEditingService = accessor.get(IWorkspaceEditingService); const dialogsService = accessor.get(IFileDialogService); const folders = await dialogsService.showOpenDialog({ - openLabel: mnemonicButtonLabel(nls.localize({ key: 'add', comment: ['&& denotes a mnemonic'] }, "&&Add")), - title: nls.localize('addFolderToWorkspaceTitle', "Add Folder to Workspace"), + openLabel: mnemonicButtonLabel(localize({ key: 'add', comment: ['&& denotes a mnemonic'] }, "&&Add")), + title: localize('addFolderToWorkspaceTitle', "Add Folder to Workspace"), canSelectFolders: true, canSelectMany: true, defaultUri: await dialogsService.defaultFolderPath() @@ -72,7 +72,7 @@ CommandsRegistry.registerCommand({ return; } - await workspaceEditingService.addFolders(folders.map(folder => ({ uri: resources.removeTrailingPathSeparator(folder) }))); + await workspaceEditingService.addFolders(folders.map(folder => ({ uri: removeTrailingPathSeparator(folder) }))); } }); @@ -91,7 +91,7 @@ CommandsRegistry.registerCommand(PICK_WORKSPACE_FOLDER_COMMAND_ID, async functio const folderPicks: IQuickPickItem[] = folders.map(folder => { return { label: folder.name, - description: labelService.getUriLabel(resources.dirname(folder.uri), { relative: true }), + description: labelService.getUriLabel(dirname(folder.uri), { relative: true }), folder, iconClasses: getIconClasses(modelService, modeService, folder.uri, FileKind.ROOT_FOLDER) }; @@ -104,7 +104,7 @@ CommandsRegistry.registerCommand(PICK_WORKSPACE_FOLDER_COMMAND_ID, async functio } if (!options.placeHolder) { - options.placeHolder = nls.localize('workspaceFolderPickerPlaceholder', "Select workspace folder"); + options.placeHolder = localize('workspaceFolderPickerPlaceholder', "Select workspace folder"); } if (typeof options.matchOnDescription !== 'boolean') { diff --git a/src/vs/workbench/browser/parts/compositeBar.ts b/src/vs/workbench/browser/parts/compositeBar.ts index 94fccfcb646..d96f65dff94 100644 --- a/src/vs/workbench/browser/parts/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositeBar.ts @@ -3,10 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { IAction, toAction } from 'vs/base/common/actions'; import { illegalArgument } from 'vs/base/common/errors'; -import * as arrays from 'vs/base/common/arrays'; +import { equals } from 'vs/base/common/arrays'; import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { IBadge } from 'vs/workbench/services/activity/common/activity'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -224,7 +224,7 @@ export class CompositeBar extends Widget implements ICompositeBar { ); }, orientation: this.options.orientation, - ariaLabel: nls.localize('activityBarAriaLabel', "Active View Switcher"), + ariaLabel: localize('activityBarAriaLabel', "Active View Switcher"), animated: false, preventLoopNavigation: this.options.preventLoopNavigation, triggerKeys: { keyDown: true } @@ -538,7 +538,7 @@ export class CompositeBar extends Widget implements ICompositeBar { compositesToShow.length ? compositesToShow.splice(compositesToShow.length - 2, 1) : compositesToShow.pop(); } - const visibleCompositesChange = !arrays.equals(compositesToShow, this.visibleComposites); + const visibleCompositesChange = !equals(compositesToShow, this.visibleComposites); // Pull out overflow action if there is a composite change so that we can add it to the end later if (this.compositeOverflowAction && visibleCompositesChange) { diff --git a/src/vs/workbench/browser/parts/compositeBarActions.ts b/src/vs/workbench/browser/parts/compositeBarActions.ts index 3aac3df41ee..ee3b38958e1 100644 --- a/src/vs/workbench/browser/parts/compositeBarActions.ts +++ b/src/vs/workbench/browser/parts/compositeBarActions.ts @@ -3,9 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { Action, IAction, Separator } from 'vs/base/common/actions'; -import * as dom from 'vs/base/browser/dom'; +import { $, addDisposableListener, append, clearNode, EventHelper, EventType, getDomNodePagePosition, hide, show } from 'vs/base/browser/dom'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { dispose, toDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; @@ -208,11 +208,11 @@ export class ActivityActionViewItem extends BaseActionViewItem { } // Try hard to prevent keyboard only focus feedback when using mouse - this._register(dom.addDisposableListener(this.container, dom.EventType.MOUSE_DOWN, () => { + this._register(addDisposableListener(this.container, EventType.MOUSE_DOWN, () => { this.container.classList.add('clicked'); })); - this._register(dom.addDisposableListener(this.container, dom.EventType.MOUSE_UP, () => { + this._register(addDisposableListener(this.container, EventType.MOUSE_UP, () => { if (this.mouseUpTimeout) { clearTimeout(this.mouseUpTimeout); } @@ -223,19 +223,19 @@ export class ActivityActionViewItem extends BaseActionViewItem { })); // Label - this.label = dom.append(container, dom.$('a')); + this.label = append(container, $('a')); // Badge - this.badge = dom.append(container, dom.$('.badge')); - this.badgeContent = dom.append(this.badge, dom.$('.badge-content')); + this.badge = append(container, $('.badge')); + this.badgeContent = append(this.badge, $('.badge-content')); // Activity bar active border + background const isActivityBarItem = this.options.icon; if (isActivityBarItem) { - dom.append(container, dom.$('.active-item-indicator')); + append(container, $('.active-item-indicator')); } - dom.hide(this.badge); + hide(this.badge); this.updateActivity(); this.updateStyles(); @@ -263,8 +263,8 @@ export class ActivityActionViewItem extends BaseActionViewItem { this.badgeDisposable.clear(); - dom.clearNode(this.badgeContent); - dom.hide(this.badge); + clearNode(this.badgeContent); + hide(this.badge); if (badge) { @@ -282,26 +282,26 @@ export class ActivityActionViewItem extends BaseActionViewItem { } } this.badgeContent.textContent = number; - dom.show(this.badge); + show(this.badge); } } // Text else if (badge instanceof TextBadge) { this.badgeContent.textContent = badge.text; - dom.show(this.badge); + show(this.badge); } // Icon else if (badge instanceof IconBadge) { const clazzList = ThemeIcon.asClassNameArray(badge.icon); this.badgeContent.classList.add(...clazzList); - dom.show(this.badge); + show(this.badge); } // Progress else if (badge instanceof ProgressBadge) { - dom.show(this.badge); + show(this.badge); } if (clazz) { @@ -314,7 +314,7 @@ export class ActivityActionViewItem extends BaseActionViewItem { let title: string; if (badge?.getDescription()) { if (this.activity.name) { - title = nls.localize('badgeTitle', "{0} - {1}", this.activity.name, badge.getDescription()); + title = localize('badgeTitle', "{0} - {1}", this.activity.name, badge.getDescription()); } else { title = badge.getDescription(); } @@ -369,7 +369,7 @@ export class CompositeOverflowActivityAction extends ActivityAction { ) { super({ id: 'additionalComposites.action', - name: nls.localize('additionalViews', "Additional Views"), + name: localize('additionalViews', "Additional Views"), cssClass: Codicon.more.classNames }); } @@ -424,7 +424,7 @@ export class CompositeOverflowActivityActionViewItem extends ActivityActionViewI } if (suffix) { - action.label = nls.localize('numberBadge', "{0} ({1})", composite.name, suffix); + action.label = localize('numberBadge', "{0} ({1})", composite.name, suffix); } else { action.label = composite.name || ''; } @@ -447,7 +447,7 @@ class ManageExtensionAction extends Action { constructor( @ICommandService private readonly commandService: ICommandService ) { - super('activitybar.manage.extension', nls.localize('manageExtension', "Manage Extension")); + super('activitybar.manage.extension', localize('manageExtension', "Manage Extension")); } run(id: string): Promise { @@ -513,7 +513,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem { } const keybinding = this.compositeActivityAction.activity.keybindingId ? this.keybindingService.lookupKeybinding(this.compositeActivityAction.activity.keybindingId) : null; - return keybinding ? nls.localize('titleKeybinding', "{0} ({1})", name, keybinding.getLabel()) : name; + return keybinding ? localize('titleKeybinding', "{0} ({1})", name, keybinding.getLabel()) : name; } render(container: HTMLElement): void { @@ -522,8 +522,8 @@ export class CompositeActionViewItem extends ActivityActionViewItem { this.updateChecked(); this.updateEnabled(); - this._register(dom.addDisposableListener(this.container, dom.EventType.CONTEXT_MENU, e => { - dom.EventHelper.stop(e, true); + this._register(addDisposableListener(this.container, EventType.CONTEXT_MENU, e => { + EventHelper.stop(e, true); this.showContextMenu(container); })); @@ -546,7 +546,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem { }, onDrop: e => { - dom.EventHelper.stop(e.eventData, true); + EventHelper.stop(e.eventData, true); this.dndHandler.drop(e.dragAndDropData, this.activity.id, e.eventData, insertDropBefore); insertDropBefore = this.updateFromDragging(container, false, e.eventData); }, @@ -626,10 +626,10 @@ export class CompositeActionViewItem extends ActivityActionViewItem { const isPinned = this.compositeBar.isPinned(this.activity.id); if (isPinned) { - this.toggleCompositePinnedAction.label = nls.localize('hide', "Hide '{0}'", this.getActivtyName(true)); + this.toggleCompositePinnedAction.label = localize('hide', "Hide '{0}'", this.getActivtyName(true)); this.toggleCompositePinnedAction.checked = false; } else { - this.toggleCompositePinnedAction.label = nls.localize('keep', "Keep '{0}'", this.getActivtyName(true)); + this.toggleCompositePinnedAction.label = localize('keep', "Keep '{0}'", this.getActivtyName(true)); } const otherActions = this.contextMenuActionsProvider(); @@ -638,7 +638,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem { actions.push(...otherActions); } - const elementPosition = dom.getDomNodePagePosition(container); + const elementPosition = getDomNodePagePosition(container); const anchor = { x: Math.floor(elementPosition.left + (elementPosition.width / 2)), y: elementPosition.top + elementPosition.height @@ -690,7 +690,7 @@ export class ToggleCompositePinnedAction extends Action { private activity: IActivity | undefined, private compositeBar: ICompositeBar ) { - super('show.toggleCompositePinned', activity ? activity.name : nls.localize('toggle', "Toggle View Pinned")); + super('show.toggleCompositePinned', activity ? activity.name : localize('toggle', "Toggle View Pinned")); this.checked = !!this.activity && this.compositeBar.isPinned(this.activity.id); } diff --git a/src/vs/workbench/browser/parts/compositePart.ts b/src/vs/workbench/browser/parts/compositePart.ts index 3e7f9fb96cf..5f9b29f4587 100644 --- a/src/vs/workbench/browser/parts/compositePart.ts +++ b/src/vs/workbench/browser/parts/compositePart.ts @@ -4,11 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/compositepart'; -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { defaultGenerator } from 'vs/base/common/idGenerator'; import { IDisposable, dispose, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; import { Emitter } from 'vs/base/common/event'; -import * as errors from 'vs/base/common/errors'; +import { isPromiseCanceledError } from 'vs/base/common/errors'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; import { ActionsOrientation, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar'; import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; @@ -258,7 +258,7 @@ export abstract class CompositePart extends Part { this.telemetryActionsListener.value = toolBar.actionRunner.onDidRun(e => { // Check for Error - if (e.error && !errors.isPromiseCanceledError(e.error)) { + if (e.error && !isPromiseCanceledError(e.error)) { this.notificationService.error(e.error); } @@ -318,7 +318,7 @@ export abstract class CompositePart extends Part { this.titleLabel.updateTitle(compositeId, compositeTitle, withNullAsUndefined(keybinding?.getLabel())); const toolBar = assertIsDefined(this.toolBar); - toolBar.setAriaLabel(nls.localize('ariaCompositeToolbarLabel', "{0} actions", compositeTitle)); + toolBar.setAriaLabel(localize('ariaCompositeToolbarLabel', "{0} actions", compositeTitle)); } private collectCompositeActions(composite?: Composite): () => void { @@ -394,7 +394,7 @@ export abstract class CompositePart extends Part { orientation: ActionsOrientation.HORIZONTAL, getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id), anchorAlignmentProvider: () => this.getTitleAreaDropDownAnchorAlignment(), - toggleMenuTitle: nls.localize('viewsAndMoreActions', "Views and More Actions...") + toggleMenuTitle: localize('viewsAndMoreActions', "Views and More Actions...") })); this.collectCompositeActions()(); @@ -413,7 +413,7 @@ export abstract class CompositePart extends Part { // The title label is shared for all composites in the base CompositePart if (!this.activeComposite || this.activeComposite.getId() === id) { titleLabel.innerText = title; - titleLabel.title = keybinding ? nls.localize('titleTooltip', "{0} ({1})", title, keybinding) : title; + titleLabel.title = keybinding ? localize('titleTooltip', "{0} ({1})", title, keybinding) : title; } }, diff --git a/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts b/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts index 83550c00b8e..babf68f0dfa 100644 --- a/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts +++ b/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { IDialogOptions, IConfirmation, IConfirmationResult, DialogType, IShowResult, IInputResult, ICheckbox, IInput, IDialogHandler } from 'vs/platform/dialogs/common/dialogs'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { ILogService } from 'vs/platform/log/common/log'; @@ -46,13 +46,13 @@ export class BrowserDialogHandler implements IDialogHandler { if (confirmation.primaryButton) { buttons.push(confirmation.primaryButton); } else { - buttons.push(nls.localize({ key: 'yesButton', comment: ['&& denotes a mnemonic'] }, "&&Yes")); + buttons.push(localize({ key: 'yesButton', comment: ['&& denotes a mnemonic'] }, "&&Yes")); } if (confirmation.secondaryButton) { buttons.push(confirmation.secondaryButton); } else if (typeof confirmation.secondaryButton === 'undefined') { - buttons.push(nls.localize('cancelButton', "Cancel")); + buttons.push(localize('cancelButton', "Cancel")); } const result = await this.doShow(confirmation.type, confirmation.message, buttons, confirmation.detail, 1, confirmation.checkbox); @@ -121,7 +121,7 @@ export class BrowserDialogHandler implements IDialogHandler { async about(): Promise { const detailString = (useAgo: boolean): string => { - return nls.localize('aboutDetail', + return localize('aboutDetail', "Version: {0}\nCommit: {1}\nDate: {2}\nBrowser: {3}", this.productService.version || 'Unknown', this.productService.commit || 'Unknown', @@ -134,7 +134,7 @@ export class BrowserDialogHandler implements IDialogHandler { const detailToCopy = detailString(false); - const { choice } = await this.show(Severity.Info, this.productService.nameLong, [nls.localize('copy', "Copy"), nls.localize('ok', "OK")], { detail, cancelId: 1 }); + const { choice } = await this.show(Severity.Info, this.productService.nameLong, [localize('copy', "Copy"), localize('ok', "OK")], { detail, cancelId: 1 }); if (choice === 0) { this.clipboardService.writeText(detailToCopy); diff --git a/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts b/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts index 9d285cea910..1e3ebf38f8f 100644 --- a/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { BINARY_DIFF_EDITOR_ID } from 'vs/workbench/common/editor'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -33,7 +33,7 @@ export class BinaryResourceDiffEditor extends SideBySideEditor { const secondary = this.secondaryEditorPane; if (primary instanceof BaseBinaryResourceEditor && secondary instanceof BaseBinaryResourceEditor) { - return nls.localize('metadataDiff', "{0} ↔ {1}", secondary.getMetadata(), primary.getMetadata()); + return localize('metadataDiff', "{0} ↔ {1}", secondary.getMetadata(), primary.getMetadata()); } return undefined; diff --git a/src/vs/workbench/browser/parts/editor/binaryEditor.ts b/src/vs/workbench/browser/parts/editor/binaryEditor.ts index 0883f8f85ce..5129069e370 100644 --- a/src/vs/workbench/browser/parts/editor/binaryEditor.ts +++ b/src/vs/workbench/browser/parts/editor/binaryEditor.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/binaryeditor'; -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { Emitter } from 'vs/base/common/event'; import { EditorInput, EditorOptions, IEditorOpenContext } from 'vs/workbench/common/editor'; import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; @@ -58,7 +58,7 @@ export abstract class BaseBinaryResourceEditor extends EditorPane { } getTitle(): string { - return this.input ? this.input.getName() : nls.localize('binaryEditor', "Binary Viewer"); + return this.input ? this.input.getName() : localize('binaryEditor', "Binary Viewer"); } protected createEditor(parent: HTMLElement): void { @@ -217,7 +217,7 @@ class FileTooLargeFileView { clearNode(container); const label = document.createElement('span'); - label.textContent = nls.localize('nativeFileTooLargeError', "The file is not displayed in the editor because it is too large ({0}).", size); + label.textContent = localize('nativeFileTooLargeError', "The file is not displayed in the editor because it is too large ({0}).", size); container.appendChild(label); scrollbar.scanDomNode(); @@ -240,12 +240,12 @@ class FileSeemsBinaryFileView { const disposables = new DisposableStore(); const label = document.createElement('p'); - label.textContent = nls.localize('nativeBinaryError', "The file is not displayed in the editor because it is either binary or uses an unsupported text encoding."); + label.textContent = localize('nativeBinaryError', "The file is not displayed in the editor because it is either binary or uses an unsupported text encoding."); container.appendChild(label); const link = append(label, $('a.embedded-link')); link.setAttribute('role', 'button'); - link.textContent = nls.localize('openAsText', "Do you want to open it anyway?"); + link.textContent = localize('openAsText', "Do you want to open it anyway?"); disposables.add(addDisposableListener(link, EventType.CLICK, () => delegate.openInternalClb(descriptor.resource))); diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index e7002d6b68c..dc5a50fa00d 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Registry } from 'vs/platform/registry/common/platform'; -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; import { EditorInput, IEditorInputFactory, SideBySideEditorInput, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions, TextCompareEditorActiveContext, ActiveEditorPinnedContext, EditorGroupEditorsCountContext, ActiveEditorStickyContext, ActiveEditorAvailableEditorIdsContext, MultipleEditorGroupsContext, ActiveEditorDirtyContext } from 'vs/workbench/common/editor'; @@ -35,7 +35,12 @@ import { NewEditorGroupAboveAction, NewEditorGroupBelowAction, SplitEditorOrthogonalAction, CloseEditorInAllGroupsAction, NavigateToLastEditLocationAction, ToggleGroupSizesAction, ShowAllEditorsByMostRecentlyUsedAction, QuickAccessPreviousRecentlyUsedEditorAction, OpenPreviousRecentlyUsedEditorInGroupAction, OpenNextRecentlyUsedEditorInGroupAction, QuickAccessLeastRecentlyUsedEditorAction, QuickAccessLeastRecentlyUsedEditorInGroupAction, ReopenResourcesAction, ToggleEditorTypeAction, DuplicateGroupDownAction, DuplicateGroupLeftAction, DuplicateGroupRightAction, DuplicateGroupUpAction } from 'vs/workbench/browser/parts/editor/editorActions'; -import * as editorCommands from 'vs/workbench/browser/parts/editor/editorCommands'; +import { + CLOSE_EDITORS_AND_GROUP_COMMAND_ID, CLOSE_EDITORS_IN_GROUP_COMMAND_ID, CLOSE_EDITORS_TO_THE_RIGHT_COMMAND_ID, CLOSE_EDITOR_COMMAND_ID, CLOSE_EDITOR_GROUP_COMMAND_ID, + CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID, CLOSE_PINNED_EDITOR_COMMAND_ID, CLOSE_SAVED_EDITORS_COMMAND_ID, GOTO_NEXT_CHANGE, GOTO_PREVIOUS_CHANGE, KEEP_EDITOR_COMMAND_ID, + PIN_EDITOR_COMMAND_ID, SHOW_EDITORS_IN_GROUP, SPLIT_EDITOR_DOWN, SPLIT_EDITOR_LEFT, SPLIT_EDITOR_RIGHT, SPLIT_EDITOR_UP, TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE, + TOGGLE_DIFF_SIDE_BY_SIDE, TOGGLE_KEEP_EDITORS_COMMAND_ID, UNPIN_EDITOR_COMMAND_ID, setup +} from 'vs/workbench/browser/parts/editor/editorCommands'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { inQuickPickContext, getQuickNavigateHandler } from 'vs/workbench/browser/quickaccess'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -64,7 +69,7 @@ Registry.as(EditorExtensions.Editors).registerEditor( EditorDescriptor.create( TextResourceEditor, TextResourceEditor.ID, - nls.localize('textEditor', "Text Editor"), + localize('textEditor', "Text Editor"), ), [ new SyncDescriptor(UntitledTextEditorInput), @@ -77,7 +82,7 @@ Registry.as(EditorExtensions.Editors).registerEditor( EditorDescriptor.create( TextDiffEditor, TextDiffEditor.ID, - nls.localize('textDiffEditor', "Text Diff Editor") + localize('textDiffEditor', "Text Diff Editor") ), [ new SyncDescriptor(DiffEditorInput) @@ -89,7 +94,7 @@ Registry.as(EditorExtensions.Editors).registerEditor( EditorDescriptor.create( BinaryResourceDiffEditor, BinaryResourceDiffEditor.ID, - nls.localize('binaryDiffEditor', "Binary Diff Editor") + localize('binaryDiffEditor', "Binary Diff Editor") ), [ new SyncDescriptor(DiffEditorInput) @@ -100,7 +105,7 @@ Registry.as(EditorExtensions.Editors).registerEditor( EditorDescriptor.create( SideBySideEditor, SideBySideEditor.ID, - nls.localize('sideBySideEditor', "Side by Side Editor") + localize('sideBySideEditor', "Side by Side Editor") ), [ new SyncDescriptor(SideBySideEditorInput) @@ -295,24 +300,24 @@ quickAccessRegistry.registerQuickAccessProvider({ ctor: ActiveGroupEditorsByMostRecentlyUsedQuickAccess, prefix: ActiveGroupEditorsByMostRecentlyUsedQuickAccess.PREFIX, contextKey: editorPickerContextKey, - placeholder: nls.localize('editorQuickAccessPlaceholder', "Type the name of an editor to open it."), - helpEntries: [{ description: nls.localize('activeGroupEditorsByMostRecentlyUsedQuickAccess', "Show Editors in Active Group by Most Recently Used"), needsEditor: false }] + placeholder: localize('editorQuickAccessPlaceholder', "Type the name of an editor to open it."), + helpEntries: [{ description: localize('activeGroupEditorsByMostRecentlyUsedQuickAccess', "Show Editors in Active Group by Most Recently Used"), needsEditor: false }] }); quickAccessRegistry.registerQuickAccessProvider({ ctor: AllEditorsByAppearanceQuickAccess, prefix: AllEditorsByAppearanceQuickAccess.PREFIX, contextKey: editorPickerContextKey, - placeholder: nls.localize('editorQuickAccessPlaceholder', "Type the name of an editor to open it."), - helpEntries: [{ description: nls.localize('allEditorsByAppearanceQuickAccess', "Show All Opened Editors By Appearance"), needsEditor: false }] + placeholder: localize('editorQuickAccessPlaceholder', "Type the name of an editor to open it."), + helpEntries: [{ description: localize('allEditorsByAppearanceQuickAccess', "Show All Opened Editors By Appearance"), needsEditor: false }] }); quickAccessRegistry.registerQuickAccessProvider({ ctor: AllEditorsByMostRecentlyUsedQuickAccess, prefix: AllEditorsByMostRecentlyUsedQuickAccess.PREFIX, contextKey: editorPickerContextKey, - placeholder: nls.localize('editorQuickAccessPlaceholder', "Type the name of an editor to open it."), - helpEntries: [{ description: nls.localize('allEditorsByMostRecentlyUsedQuickAccess', "Show All Opened Editors By Most Recently Used"), needsEditor: false }] + placeholder: localize('editorQuickAccessPlaceholder', "Type the name of an editor to open it."), + helpEntries: [{ description: localize('allEditorsByMostRecentlyUsedQuickAccess', "Show All Opened Editors By Most Recently Used"), needsEditor: false }] }); // Register Editor Actions @@ -330,7 +335,7 @@ registry.registerWorkbenchAction(SyncActionDescriptor.from(ReopenClosedEditorAct registry.registerWorkbenchAction(SyncActionDescriptor.from(ShowAllEditorsByAppearanceAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_P), mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Tab } }), 'View: Show All Editors By Appearance', CATEGORIES.View.value); registry.registerWorkbenchAction(SyncActionDescriptor.from(ShowAllEditorsByMostRecentlyUsedAction), 'View: Show All Editors By Most Recently Used', CATEGORIES.View.value); registry.registerWorkbenchAction(SyncActionDescriptor.from(ShowEditorsInActiveGroupByMostRecentlyUsedAction), 'View: Show Editors in Active Group By Most Recently Used', CATEGORIES.View.value); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ClearRecentFilesAction), 'File: Clear Recently Opened', nls.localize('file', "File")); +registry.registerWorkbenchAction(SyncActionDescriptor.from(ClearRecentFilesAction), 'File: Clear Recently Opened', localize('file', "File")); registry.registerWorkbenchAction(SyncActionDescriptor.from(CloseAllEditorsAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_W) }), 'View: Close All Editors', CATEGORIES.View.value); registry.registerWorkbenchAction(SyncActionDescriptor.from(CloseAllEditorGroupsAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_W) }), 'View: Close All Editor Groups', CATEGORIES.View.value); registry.registerWorkbenchAction(SyncActionDescriptor.from(CloseLeftEditorsInGroupAction), 'View: Close Editors to the Left in Group', CATEGORIES.View.value); @@ -428,7 +433,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ }); // Editor Commands -editorCommands.setup(); +setup(); // Touch Bar if (isMacintosh) { @@ -446,34 +451,34 @@ if (isMacintosh) { } // Empty Editor Group Context Menu -MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: editorCommands.SPLIT_EDITOR_UP, title: nls.localize('splitUp', "Split Up") }, group: '2_split', order: 10 }); -MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: editorCommands.SPLIT_EDITOR_DOWN, title: nls.localize('splitDown', "Split Down") }, group: '2_split', order: 20 }); -MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: editorCommands.SPLIT_EDITOR_LEFT, title: nls.localize('splitLeft', "Split Left") }, group: '2_split', order: 30 }); -MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: editorCommands.SPLIT_EDITOR_RIGHT, title: nls.localize('splitRight', "Split Right") }, group: '2_split', order: 40 }); -MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: editorCommands.CLOSE_EDITOR_GROUP_COMMAND_ID, title: nls.localize('close', "Close") }, group: '3_close', order: 10, when: ContextKeyExpr.has('multipleEditorGroups') }); +MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: SPLIT_EDITOR_UP, title: localize('splitUp', "Split Up") }, group: '2_split', order: 10 }); +MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: SPLIT_EDITOR_DOWN, title: localize('splitDown', "Split Down") }, group: '2_split', order: 20 }); +MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: SPLIT_EDITOR_LEFT, title: localize('splitLeft', "Split Left") }, group: '2_split', order: 30 }); +MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: SPLIT_EDITOR_RIGHT, title: localize('splitRight', "Split Right") }, group: '2_split', order: 40 }); +MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: CLOSE_EDITOR_GROUP_COMMAND_ID, title: localize('close', "Close") }, group: '3_close', order: 10, when: ContextKeyExpr.has('multipleEditorGroups') }); // Editor Title Context Menu -MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.CLOSE_EDITOR_COMMAND_ID, title: nls.localize('close', "Close") }, group: '1_close', order: 10 }); -MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID, title: nls.localize('closeOthers', "Close Others"), precondition: EditorGroupEditorsCountContext.notEqualsTo('1') }, group: '1_close', order: 20 }); -MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.CLOSE_EDITORS_TO_THE_RIGHT_COMMAND_ID, title: nls.localize('closeRight', "Close to the Right"), precondition: EditorGroupEditorsCountContext.notEqualsTo('1') }, group: '1_close', order: 30, when: ContextKeyExpr.has('config.workbench.editor.showTabs') }); -MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.CLOSE_SAVED_EDITORS_COMMAND_ID, title: nls.localize('closeAllSaved', "Close Saved") }, group: '1_close', order: 40 }); -MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: nls.localize('closeAll', "Close All") }, group: '1_close', order: 50 }); +MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: CLOSE_EDITOR_COMMAND_ID, title: localize('close', "Close") }, group: '1_close', order: 10 }); +MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID, title: localize('closeOthers', "Close Others"), precondition: EditorGroupEditorsCountContext.notEqualsTo('1') }, group: '1_close', order: 20 }); +MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: CLOSE_EDITORS_TO_THE_RIGHT_COMMAND_ID, title: localize('closeRight', "Close to the Right"), precondition: EditorGroupEditorsCountContext.notEqualsTo('1') }, group: '1_close', order: 30, when: ContextKeyExpr.has('config.workbench.editor.showTabs') }); +MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: CLOSE_SAVED_EDITORS_COMMAND_ID, title: localize('closeAllSaved', "Close Saved") }, group: '1_close', order: 40 }); +MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: localize('closeAll', "Close All") }, group: '1_close', order: 50 }); MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: ReopenResourcesAction.ID, title: ReopenResourcesAction.LABEL }, group: '1_open', order: 10, when: ActiveEditorAvailableEditorIdsContext }); -MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.KEEP_EDITOR_COMMAND_ID, title: nls.localize('keepOpen', "Keep Open"), precondition: ActiveEditorPinnedContext.toNegated() }, group: '3_preview', order: 10, when: ContextKeyExpr.has('config.workbench.editor.enablePreview') }); -MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.PIN_EDITOR_COMMAND_ID, title: nls.localize('pin', "Pin") }, group: '3_preview', order: 20, when: ActiveEditorStickyContext.toNegated() }); -MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.UNPIN_EDITOR_COMMAND_ID, title: nls.localize('unpin', "Unpin") }, group: '3_preview', order: 20, when: ActiveEditorStickyContext }); -MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.SPLIT_EDITOR_UP, title: nls.localize('splitUp', "Split Up") }, group: '5_split', order: 10 }); -MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.SPLIT_EDITOR_DOWN, title: nls.localize('splitDown', "Split Down") }, group: '5_split', order: 20 }); -MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.SPLIT_EDITOR_LEFT, title: nls.localize('splitLeft', "Split Left") }, group: '5_split', order: 30 }); -MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.SPLIT_EDITOR_RIGHT, title: nls.localize('splitRight', "Split Right") }, group: '5_split', order: 40 }); +MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: KEEP_EDITOR_COMMAND_ID, title: localize('keepOpen', "Keep Open"), precondition: ActiveEditorPinnedContext.toNegated() }, group: '3_preview', order: 10, when: ContextKeyExpr.has('config.workbench.editor.enablePreview') }); +MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: PIN_EDITOR_COMMAND_ID, title: localize('pin', "Pin") }, group: '3_preview', order: 20, when: ActiveEditorStickyContext.toNegated() }); +MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: UNPIN_EDITOR_COMMAND_ID, title: localize('unpin', "Unpin") }, group: '3_preview', order: 20, when: ActiveEditorStickyContext }); +MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: SPLIT_EDITOR_UP, title: localize('splitUp', "Split Up") }, group: '5_split', order: 10 }); +MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: SPLIT_EDITOR_DOWN, title: localize('splitDown', "Split Down") }, group: '5_split', order: 20 }); +MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: SPLIT_EDITOR_LEFT, title: localize('splitLeft', "Split Left") }, group: '5_split', order: 30 }); +MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: SPLIT_EDITOR_RIGHT, title: localize('splitRight', "Split Right") }, group: '5_split', order: 40 }); // Editor Title Menu -MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.TOGGLE_DIFF_SIDE_BY_SIDE, title: nls.localize('inlineView', "Inline View"), toggled: ContextKeyExpr.equals('config.diffEditor.renderSideBySide', false) }, group: '1_diff', order: 10, when: ContextKeyExpr.has('isInDiffEditor') }); -MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.SHOW_EDITORS_IN_GROUP, title: nls.localize('showOpenedEditors', "Show Opened Editors") }, group: '3_open', order: 10 }); -MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: nls.localize('closeAll', "Close All") }, group: '5_close', order: 10 }); -MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.CLOSE_SAVED_EDITORS_COMMAND_ID, title: nls.localize('closeAllSaved', "Close Saved") }, group: '5_close', order: 20 }); -MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.TOGGLE_KEEP_EDITORS_COMMAND_ID, title: nls.localize('toggleKeepEditors', "Keep Editors Open"), toggled: ContextKeyExpr.not('config.workbench.editor.enablePreview') }, group: '7_settings', order: 10 }); -MenuRegistry.appendMenuItem(MenuId.EditorTitle, { submenu: MenuId.EditorTitleRun, title: { value: nls.localize('run', "Run"), original: 'Run', }, icon: Codicon.run, group: 'navigation', order: -1 }); +MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: TOGGLE_DIFF_SIDE_BY_SIDE, title: localize('inlineView', "Inline View"), toggled: ContextKeyExpr.equals('config.diffEditor.renderSideBySide', false) }, group: '1_diff', order: 10, when: ContextKeyExpr.has('isInDiffEditor') }); +MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: SHOW_EDITORS_IN_GROUP, title: localize('showOpenedEditors', "Show Opened Editors") }, group: '3_open', order: 10 }); +MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: localize('closeAll', "Close All") }, group: '5_close', order: 10 }); +MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: CLOSE_SAVED_EDITORS_COMMAND_ID, title: localize('closeAllSaved', "Close Saved") }, group: '5_close', order: 20 }); +MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: TOGGLE_KEEP_EDITORS_COMMAND_ID, title: localize('toggleKeepEditors', "Keep Editors Open"), toggled: ContextKeyExpr.not('config.workbench.editor.enablePreview') }, group: '7_settings', order: 10 }); +MenuRegistry.appendMenuItem(MenuId.EditorTitle, { submenu: MenuId.EditorTitleRun, title: { value: localize('run', "Run"), original: 'Run', }, icon: Codicon.run, group: 'navigation', order: -1 }); interface IEditorToolItem { id: string; title: string; icon?: { dark?: URI; light?: URI; } | ThemeIcon; } @@ -505,14 +510,14 @@ function appendEditorToolItem(primary: IEditorToolItem, when: ContextKeyExpressi appendEditorToolItem( { id: SplitEditorAction.ID, - title: nls.localize('splitEditorRight', "Split Editor Right"), + title: localize('splitEditorRight', "Split Editor Right"), icon: Codicon.splitHorizontal }, ContextKeyExpr.not('splitEditorsVertically'), 100000, // towards the end { - id: editorCommands.SPLIT_EDITOR_DOWN, - title: nls.localize('splitEditorDown', "Split Editor Down"), + id: SPLIT_EDITOR_DOWN, + title: localize('splitEditorDown', "Split Editor Down"), icon: Codicon.splitVertical } ); @@ -520,14 +525,14 @@ appendEditorToolItem( appendEditorToolItem( { id: SplitEditorAction.ID, - title: nls.localize('splitEditorDown', "Split Editor Down"), + title: localize('splitEditorDown', "Split Editor Down"), icon: Codicon.splitVertical }, ContextKeyExpr.has('splitEditorsVertically'), 100000, // towards the end { - id: editorCommands.SPLIT_EDITOR_RIGHT, - title: nls.localize('splitEditorRight', "Split Editor Right"), + id: SPLIT_EDITOR_RIGHT, + title: localize('splitEditorRight', "Split Editor Right"), icon: Codicon.splitHorizontal } ); @@ -535,15 +540,15 @@ appendEditorToolItem( // Editor Title Menu: Close (tabs disabled, normal editor) appendEditorToolItem( { - id: editorCommands.CLOSE_EDITOR_COMMAND_ID, - title: nls.localize('close', "Close"), + id: CLOSE_EDITOR_COMMAND_ID, + title: localize('close', "Close"), icon: Codicon.close }, ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ActiveEditorDirtyContext.toNegated(), ActiveEditorStickyContext.toNegated()), 1000000, // towards the far end { - id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, - title: nls.localize('closeAll', "Close All"), + id: CLOSE_EDITORS_IN_GROUP_COMMAND_ID, + title: localize('closeAll', "Close All"), icon: Codicon.closeAll } ); @@ -551,15 +556,15 @@ appendEditorToolItem( // Editor Title Menu: Close (tabs disabled, dirty editor) appendEditorToolItem( { - id: editorCommands.CLOSE_EDITOR_COMMAND_ID, - title: nls.localize('close', "Close"), + id: CLOSE_EDITOR_COMMAND_ID, + title: localize('close', "Close"), icon: Codicon.closeDirty }, ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ActiveEditorDirtyContext, ActiveEditorStickyContext.toNegated()), 1000000, // towards the far end { - id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, - title: nls.localize('closeAll', "Close All"), + id: CLOSE_EDITORS_IN_GROUP_COMMAND_ID, + title: localize('closeAll', "Close All"), icon: Codicon.closeAll } ); @@ -567,15 +572,15 @@ appendEditorToolItem( // Editor Title Menu: Close (tabs disabled, sticky editor) appendEditorToolItem( { - id: editorCommands.UNPIN_EDITOR_COMMAND_ID, - title: nls.localize('unpin', "Unpin"), + id: UNPIN_EDITOR_COMMAND_ID, + title: localize('unpin', "Unpin"), icon: Codicon.pinned }, ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ActiveEditorDirtyContext.toNegated(), ActiveEditorStickyContext), 1000000, // towards the far end { - id: editorCommands.CLOSE_EDITOR_COMMAND_ID, - title: nls.localize('close', "Close"), + id: CLOSE_EDITOR_COMMAND_ID, + title: localize('close', "Close"), icon: Codicon.close } ); @@ -583,29 +588,29 @@ appendEditorToolItem( // Editor Title Menu: Close (tabs disabled, dirty & sticky editor) appendEditorToolItem( { - id: editorCommands.UNPIN_EDITOR_COMMAND_ID, - title: nls.localize('unpin', "Unpin"), + id: UNPIN_EDITOR_COMMAND_ID, + title: localize('unpin', "Unpin"), icon: Codicon.pinnedDirty }, ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ActiveEditorDirtyContext, ActiveEditorStickyContext), 1000000, // towards the far end { - id: editorCommands.CLOSE_EDITOR_COMMAND_ID, - title: nls.localize('close', "Close"), + id: CLOSE_EDITOR_COMMAND_ID, + title: localize('close', "Close"), icon: Codicon.close } ); -const previousChangeIcon = registerIcon('diff-editor-previous-change', Codicon.arrowUp, nls.localize('previousChangeIcon', 'Icon for the previous change action in the diff editor.')); -const nextChangeIcon = registerIcon('diff-editor-next-change', Codicon.arrowDown, nls.localize('nextChangeIcon', 'Icon for the next change action in the diff editor.')); -const toggleWhitespace = registerIcon('diff-editor-toggle-whitespace', Codicon.whitespace, nls.localize('toggleWhitespace', 'Icon for the toggle whitespace action in the diff editor.')); +const previousChangeIcon = registerIcon('diff-editor-previous-change', Codicon.arrowUp, localize('previousChangeIcon', 'Icon for the previous change action in the diff editor.')); +const nextChangeIcon = registerIcon('diff-editor-next-change', Codicon.arrowDown, localize('nextChangeIcon', 'Icon for the next change action in the diff editor.')); +const toggleWhitespace = registerIcon('diff-editor-toggle-whitespace', Codicon.whitespace, localize('toggleWhitespace', 'Icon for the toggle whitespace action in the diff editor.')); // Diff Editor Title Menu: Previous Change appendEditorToolItem( { - id: editorCommands.GOTO_PREVIOUS_CHANGE, - title: nls.localize('navigate.prev.label', "Previous Change"), + id: GOTO_PREVIOUS_CHANGE, + title: localize('navigate.prev.label', "Previous Change"), icon: previousChangeIcon }, TextCompareEditorActiveContext, @@ -615,8 +620,8 @@ appendEditorToolItem( // Diff Editor Title Menu: Next Change appendEditorToolItem( { - id: editorCommands.GOTO_NEXT_CHANGE, - title: nls.localize('navigate.next.label', "Next Change"), + id: GOTO_NEXT_CHANGE, + title: localize('navigate.next.label', "Next Change"), icon: nextChangeIcon }, TextCompareEditorActiveContext, @@ -626,8 +631,8 @@ appendEditorToolItem( // Diff Editor Title Menu: Toggle Ignore Trim Whitespace (Enabled) appendEditorToolItem( { - id: editorCommands.TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE, - title: nls.localize('ignoreTrimWhitespace.label', "Ignore Leading/Trailing Whitespace Differences"), + id: TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE, + title: localize('ignoreTrimWhitespace.label', "Ignore Leading/Trailing Whitespace Differences"), icon: toggleWhitespace }, ContextKeyExpr.and(TextCompareEditorActiveContext, ContextKeyExpr.notEquals('config.diffEditor.ignoreTrimWhitespace', true)), @@ -637,8 +642,8 @@ appendEditorToolItem( // Diff Editor Title Menu: Toggle Ignore Trim Whitespace (Disabled) appendEditorToolItem( { - id: editorCommands.TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE, - title: nls.localize('showTrimWhitespace.label', "Show Leading/Trailing Whitespace Differences"), + id: TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE, + title: localize('showTrimWhitespace.label', "Show Leading/Trailing Whitespace Differences"), icon: ThemeIcon.modify(toggleWhitespace, 'disabled') }, ContextKeyExpr.and(TextCompareEditorActiveContext, ContextKeyExpr.notEquals('config.diffEditor.ignoreTrimWhitespace', false)), @@ -646,23 +651,23 @@ appendEditorToolItem( ); // Editor Commands for Command Palette -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.KEEP_EDITOR_COMMAND_ID, title: { value: nls.localize('keepEditor', "Keep Editor"), original: 'Keep Editor' }, category: CATEGORIES.View }, when: ContextKeyExpr.has('config.workbench.editor.enablePreview') }); -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.PIN_EDITOR_COMMAND_ID, title: { value: nls.localize('pinEditor', "Pin Editor"), original: 'Pin Editor' }, category: CATEGORIES.View } }); -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.UNPIN_EDITOR_COMMAND_ID, title: { value: nls.localize('unpinEditor', "Unpin Editor"), original: 'Unpin Editor' }, category: CATEGORIES.View } }); -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.CLOSE_EDITOR_COMMAND_ID, title: { value: nls.localize('closeEditor', "Close Editor"), original: 'Close Editor' }, category: CATEGORIES.View } }); -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.CLOSE_PINNED_EDITOR_COMMAND_ID, title: { value: nls.localize('closePinnedEditor', "Close Pinned Editor"), original: 'Close Pinned Editor' }, category: CATEGORIES.View } }); -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: { value: nls.localize('closeEditorsInGroup', "Close All Editors in Group"), original: 'Close All Editors in Group' }, category: CATEGORIES.View } }); -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.CLOSE_SAVED_EDITORS_COMMAND_ID, title: { value: nls.localize('closeSavedEditors', "Close Saved Editors in Group"), original: 'Close Saved Editors in Group' }, category: CATEGORIES.View } }); -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID, title: { value: nls.localize('closeOtherEditors', "Close Other Editors in Group"), original: 'Close Other Editors in Group' }, category: CATEGORIES.View } }); -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.CLOSE_EDITORS_TO_THE_RIGHT_COMMAND_ID, title: { value: nls.localize('closeRightEditors', "Close Editors to the Right in Group"), original: 'Close Editors to the Right in Group' }, category: CATEGORIES.View } }); -MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.CLOSE_EDITORS_AND_GROUP_COMMAND_ID, title: { value: nls.localize('closeEditorGroup', "Close Editor Group"), original: 'Close Editor Group' }, category: CATEGORIES.View }, when: MultipleEditorGroupsContext }); +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: KEEP_EDITOR_COMMAND_ID, title: { value: localize('keepEditor', "Keep Editor"), original: 'Keep Editor' }, category: CATEGORIES.View }, when: ContextKeyExpr.has('config.workbench.editor.enablePreview') }); +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: PIN_EDITOR_COMMAND_ID, title: { value: localize('pinEditor', "Pin Editor"), original: 'Pin Editor' }, category: CATEGORIES.View } }); +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: UNPIN_EDITOR_COMMAND_ID, title: { value: localize('unpinEditor', "Unpin Editor"), original: 'Unpin Editor' }, category: CATEGORIES.View } }); +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_EDITOR_COMMAND_ID, title: { value: localize('closeEditor', "Close Editor"), original: 'Close Editor' }, category: CATEGORIES.View } }); +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_PINNED_EDITOR_COMMAND_ID, title: { value: localize('closePinnedEditor', "Close Pinned Editor"), original: 'Close Pinned Editor' }, category: CATEGORIES.View } }); +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: { value: localize('closeEditorsInGroup', "Close All Editors in Group"), original: 'Close All Editors in Group' }, category: CATEGORIES.View } }); +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_SAVED_EDITORS_COMMAND_ID, title: { value: localize('closeSavedEditors', "Close Saved Editors in Group"), original: 'Close Saved Editors in Group' }, category: CATEGORIES.View } }); +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID, title: { value: localize('closeOtherEditors', "Close Other Editors in Group"), original: 'Close Other Editors in Group' }, category: CATEGORIES.View } }); +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_EDITORS_TO_THE_RIGHT_COMMAND_ID, title: { value: localize('closeRightEditors', "Close Editors to the Right in Group"), original: 'Close Editors to the Right in Group' }, category: CATEGORIES.View } }); +MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_EDITORS_AND_GROUP_COMMAND_ID, title: { value: localize('closeEditorGroup', "Close Editor Group"), original: 'Close Editor Group' }, category: CATEGORIES.View }, when: MultipleEditorGroupsContext }); // File menu MenuRegistry.appendMenuItem(MenuId.MenubarRecentMenu, { group: '1_editor', command: { id: ReopenClosedEditorAction.ID, - title: nls.localize({ key: 'miReopenClosedEditor', comment: ['&& denotes a mnemonic'] }, "&&Reopen Closed Editor"), + title: localize({ key: 'miReopenClosedEditor', comment: ['&& denotes a mnemonic'] }, "&&Reopen Closed Editor"), precondition: ContextKeyExpr.has('canReopenClosedEditor') }, order: 1 @@ -672,7 +677,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarRecentMenu, { group: 'z_clear', command: { id: ClearRecentFilesAction.ID, - title: nls.localize({ key: 'miClearRecentOpen', comment: ['&& denotes a mnemonic'] }, "&&Clear Recently Opened") + title: localize({ key: 'miClearRecentOpen', comment: ['&& denotes a mnemonic'] }, "&&Clear Recently Opened") }, order: 1 }); @@ -680,7 +685,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarRecentMenu, { // Layout menu MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { group: '2_appearance', - title: nls.localize({ key: 'miEditorLayout', comment: ['&& denotes a mnemonic'] }, "Editor &&Layout"), + title: localize({ key: 'miEditorLayout', comment: ['&& denotes a mnemonic'] }, "Editor &&Layout"), submenu: MenuId.MenubarLayoutMenu, order: 2 }); @@ -688,8 +693,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, { group: '1_split', command: { - id: editorCommands.SPLIT_EDITOR_UP, - title: nls.localize({ key: 'miSplitEditorUp', comment: ['&& denotes a mnemonic'] }, "Split &&Up") + id: SPLIT_EDITOR_UP, + title: localize({ key: 'miSplitEditorUp', comment: ['&& denotes a mnemonic'] }, "Split &&Up") }, order: 1 }); @@ -697,8 +702,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, { MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, { group: '1_split', command: { - id: editorCommands.SPLIT_EDITOR_DOWN, - title: nls.localize({ key: 'miSplitEditorDown', comment: ['&& denotes a mnemonic'] }, "Split &&Down") + id: SPLIT_EDITOR_DOWN, + title: localize({ key: 'miSplitEditorDown', comment: ['&& denotes a mnemonic'] }, "Split &&Down") }, order: 2 }); @@ -706,8 +711,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, { MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, { group: '1_split', command: { - id: editorCommands.SPLIT_EDITOR_LEFT, - title: nls.localize({ key: 'miSplitEditorLeft', comment: ['&& denotes a mnemonic'] }, "Split &&Left") + id: SPLIT_EDITOR_LEFT, + title: localize({ key: 'miSplitEditorLeft', comment: ['&& denotes a mnemonic'] }, "Split &&Left") }, order: 3 }); @@ -715,8 +720,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, { MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, { group: '1_split', command: { - id: editorCommands.SPLIT_EDITOR_RIGHT, - title: nls.localize({ key: 'miSplitEditorRight', comment: ['&& denotes a mnemonic'] }, "Split &&Right") + id: SPLIT_EDITOR_RIGHT, + title: localize({ key: 'miSplitEditorRight', comment: ['&& denotes a mnemonic'] }, "Split &&Right") }, order: 4 }); @@ -725,7 +730,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, { group: '2_layouts', command: { id: EditorLayoutSingleAction.ID, - title: nls.localize({ key: 'miSingleColumnEditorLayout', comment: ['&& denotes a mnemonic'] }, "&&Single") + title: localize({ key: 'miSingleColumnEditorLayout', comment: ['&& denotes a mnemonic'] }, "&&Single") }, order: 1 }); @@ -734,7 +739,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, { group: '2_layouts', command: { id: EditorLayoutTwoColumnsAction.ID, - title: nls.localize({ key: 'miTwoColumnsEditorLayout', comment: ['&& denotes a mnemonic'] }, "&&Two Columns") + title: localize({ key: 'miTwoColumnsEditorLayout', comment: ['&& denotes a mnemonic'] }, "&&Two Columns") }, order: 3 }); @@ -743,7 +748,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, { group: '2_layouts', command: { id: EditorLayoutThreeColumnsAction.ID, - title: nls.localize({ key: 'miThreeColumnsEditorLayout', comment: ['&& denotes a mnemonic'] }, "T&&hree Columns") + title: localize({ key: 'miThreeColumnsEditorLayout', comment: ['&& denotes a mnemonic'] }, "T&&hree Columns") }, order: 4 }); @@ -752,7 +757,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, { group: '2_layouts', command: { id: EditorLayoutTwoRowsAction.ID, - title: nls.localize({ key: 'miTwoRowsEditorLayout', comment: ['&& denotes a mnemonic'] }, "T&&wo Rows") + title: localize({ key: 'miTwoRowsEditorLayout', comment: ['&& denotes a mnemonic'] }, "T&&wo Rows") }, order: 5 }); @@ -761,7 +766,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, { group: '2_layouts', command: { id: EditorLayoutThreeRowsAction.ID, - title: nls.localize({ key: 'miThreeRowsEditorLayout', comment: ['&& denotes a mnemonic'] }, "Three &&Rows") + title: localize({ key: 'miThreeRowsEditorLayout', comment: ['&& denotes a mnemonic'] }, "Three &&Rows") }, order: 6 }); @@ -770,7 +775,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, { group: '2_layouts', command: { id: EditorLayoutTwoByTwoGridAction.ID, - title: nls.localize({ key: 'miTwoByTwoGridEditorLayout', comment: ['&& denotes a mnemonic'] }, "&&Grid (2x2)") + title: localize({ key: 'miTwoByTwoGridEditorLayout', comment: ['&& denotes a mnemonic'] }, "&&Grid (2x2)") }, order: 7 }); @@ -779,7 +784,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, { group: '2_layouts', command: { id: EditorLayoutTwoRowsRightAction.ID, - title: nls.localize({ key: 'miTwoRowsRightEditorLayout', comment: ['&& denotes a mnemonic'] }, "Two R&&ows Right") + title: localize({ key: 'miTwoRowsRightEditorLayout', comment: ['&& denotes a mnemonic'] }, "Two R&&ows Right") }, order: 8 }); @@ -788,7 +793,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, { group: '2_layouts', command: { id: EditorLayoutTwoColumnsBottomAction.ID, - title: nls.localize({ key: 'miTwoColumnsBottomEditorLayout', comment: ['&& denotes a mnemonic'] }, "Two &&Columns Bottom") + title: localize({ key: 'miTwoColumnsBottomEditorLayout', comment: ['&& denotes a mnemonic'] }, "Two &&Columns Bottom") }, order: 9 }); @@ -800,7 +805,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, { group: '1_history_nav', command: { id: 'workbench.action.navigateBack', - title: nls.localize({ key: 'miBack', comment: ['&& denotes a mnemonic'] }, "&&Back"), + title: localize({ key: 'miBack', comment: ['&& denotes a mnemonic'] }, "&&Back"), precondition: ContextKeyExpr.has('canNavigateBack') }, order: 1 @@ -810,7 +815,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, { group: '1_history_nav', command: { id: 'workbench.action.navigateForward', - title: nls.localize({ key: 'miForward', comment: ['&& denotes a mnemonic'] }, "&&Forward"), + title: localize({ key: 'miForward', comment: ['&& denotes a mnemonic'] }, "&&Forward"), precondition: ContextKeyExpr.has('canNavigateForward') }, order: 2 @@ -820,7 +825,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, { group: '1_history_nav', command: { id: 'workbench.action.navigateToLastEditLocation', - title: nls.localize({ key: 'miLastEditLocation', comment: ['&& denotes a mnemonic'] }, "&&Last Edit Location"), + title: localize({ key: 'miLastEditLocation', comment: ['&& denotes a mnemonic'] }, "&&Last Edit Location"), precondition: ContextKeyExpr.has('canNavigateToLastEditLocation') }, order: 3 @@ -831,7 +836,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, { group: '1_any', command: { id: 'workbench.action.nextEditor', - title: nls.localize({ key: 'miNextEditor', comment: ['&& denotes a mnemonic'] }, "&&Next Editor") + title: localize({ key: 'miNextEditor', comment: ['&& denotes a mnemonic'] }, "&&Next Editor") }, order: 1 }); @@ -840,7 +845,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, { group: '1_any', command: { id: 'workbench.action.previousEditor', - title: nls.localize({ key: 'miPreviousEditor', comment: ['&& denotes a mnemonic'] }, "&&Previous Editor") + title: localize({ key: 'miPreviousEditor', comment: ['&& denotes a mnemonic'] }, "&&Previous Editor") }, order: 2 }); @@ -849,7 +854,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, { group: '2_any_used', command: { id: 'workbench.action.openNextRecentlyUsedEditor', - title: nls.localize({ key: 'miNextRecentlyUsedEditor', comment: ['&& denotes a mnemonic'] }, "&&Next Used Editor") + title: localize({ key: 'miNextRecentlyUsedEditor', comment: ['&& denotes a mnemonic'] }, "&&Next Used Editor") }, order: 1 }); @@ -858,7 +863,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, { group: '2_any_used', command: { id: 'workbench.action.openPreviousRecentlyUsedEditor', - title: nls.localize({ key: 'miPreviousRecentlyUsedEditor', comment: ['&& denotes a mnemonic'] }, "&&Previous Used Editor") + title: localize({ key: 'miPreviousRecentlyUsedEditor', comment: ['&& denotes a mnemonic'] }, "&&Previous Used Editor") }, order: 2 }); @@ -867,7 +872,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, { group: '3_group', command: { id: 'workbench.action.nextEditorInGroup', - title: nls.localize({ key: 'miNextEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Next Editor in Group") + title: localize({ key: 'miNextEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Next Editor in Group") }, order: 1 }); @@ -876,7 +881,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, { group: '3_group', command: { id: 'workbench.action.previousEditorInGroup', - title: nls.localize({ key: 'miPreviousEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Previous Editor in Group") + title: localize({ key: 'miPreviousEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Previous Editor in Group") }, order: 2 }); @@ -885,7 +890,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, { group: '4_group_used', command: { id: 'workbench.action.openNextRecentlyUsedEditorInGroup', - title: nls.localize({ key: 'miNextUsedEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Next Used Editor in Group") + title: localize({ key: 'miNextUsedEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Next Used Editor in Group") }, order: 1 }); @@ -894,14 +899,14 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, { group: '4_group_used', command: { id: 'workbench.action.openPreviousRecentlyUsedEditorInGroup', - title: nls.localize({ key: 'miPreviousUsedEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Previous Used Editor in Group") + title: localize({ key: 'miPreviousUsedEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Previous Used Editor in Group") }, order: 2 }); MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, { group: '2_editor_nav', - title: nls.localize({ key: 'miSwitchEditor', comment: ['&& denotes a mnemonic'] }, "Switch &&Editor"), + title: localize({ key: 'miSwitchEditor', comment: ['&& denotes a mnemonic'] }, "Switch &&Editor"), submenu: MenuId.MenubarSwitchEditorMenu, order: 1 }); @@ -911,7 +916,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, { group: '1_focus_index', command: { id: 'workbench.action.focusFirstEditorGroup', - title: nls.localize({ key: 'miFocusFirstGroup', comment: ['&& denotes a mnemonic'] }, "Group &&1") + title: localize({ key: 'miFocusFirstGroup', comment: ['&& denotes a mnemonic'] }, "Group &&1") }, order: 1 }); @@ -920,7 +925,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, { group: '1_focus_index', command: { id: 'workbench.action.focusSecondEditorGroup', - title: nls.localize({ key: 'miFocusSecondGroup', comment: ['&& denotes a mnemonic'] }, "Group &&2") + title: localize({ key: 'miFocusSecondGroup', comment: ['&& denotes a mnemonic'] }, "Group &&2") }, order: 2 }); @@ -929,7 +934,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, { group: '1_focus_index', command: { id: 'workbench.action.focusThirdEditorGroup', - title: nls.localize({ key: 'miFocusThirdGroup', comment: ['&& denotes a mnemonic'] }, "Group &&3"), + title: localize({ key: 'miFocusThirdGroup', comment: ['&& denotes a mnemonic'] }, "Group &&3"), precondition: ContextKeyExpr.has('multipleEditorGroups') }, order: 3 @@ -939,7 +944,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, { group: '1_focus_index', command: { id: 'workbench.action.focusFourthEditorGroup', - title: nls.localize({ key: 'miFocusFourthGroup', comment: ['&& denotes a mnemonic'] }, "Group &&4"), + title: localize({ key: 'miFocusFourthGroup', comment: ['&& denotes a mnemonic'] }, "Group &&4"), precondition: ContextKeyExpr.has('multipleEditorGroups') }, order: 4 @@ -949,7 +954,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, { group: '1_focus_index', command: { id: 'workbench.action.focusFifthEditorGroup', - title: nls.localize({ key: 'miFocusFifthGroup', comment: ['&& denotes a mnemonic'] }, "Group &&5"), + title: localize({ key: 'miFocusFifthGroup', comment: ['&& denotes a mnemonic'] }, "Group &&5"), precondition: ContextKeyExpr.has('multipleEditorGroups') }, order: 5 @@ -959,7 +964,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, { group: '2_next_prev', command: { id: 'workbench.action.focusNextGroup', - title: nls.localize({ key: 'miNextGroup', comment: ['&& denotes a mnemonic'] }, "&&Next Group"), + title: localize({ key: 'miNextGroup', comment: ['&& denotes a mnemonic'] }, "&&Next Group"), precondition: ContextKeyExpr.has('multipleEditorGroups') }, order: 1 @@ -969,7 +974,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, { group: '2_next_prev', command: { id: 'workbench.action.focusPreviousGroup', - title: nls.localize({ key: 'miPreviousGroup', comment: ['&& denotes a mnemonic'] }, "&&Previous Group"), + title: localize({ key: 'miPreviousGroup', comment: ['&& denotes a mnemonic'] }, "&&Previous Group"), precondition: ContextKeyExpr.has('multipleEditorGroups') }, order: 2 @@ -979,7 +984,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, { group: '3_directional', command: { id: 'workbench.action.focusLeftGroup', - title: nls.localize({ key: 'miFocusLeftGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Left"), + title: localize({ key: 'miFocusLeftGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Left"), precondition: ContextKeyExpr.has('multipleEditorGroups') }, order: 1 @@ -989,7 +994,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, { group: '3_directional', command: { id: 'workbench.action.focusRightGroup', - title: nls.localize({ key: 'miFocusRightGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Right"), + title: localize({ key: 'miFocusRightGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Right"), precondition: ContextKeyExpr.has('multipleEditorGroups') }, order: 2 @@ -999,7 +1004,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, { group: '3_directional', command: { id: 'workbench.action.focusAboveGroup', - title: nls.localize({ key: 'miFocusAboveGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Above"), + title: localize({ key: 'miFocusAboveGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Above"), precondition: ContextKeyExpr.has('multipleEditorGroups') }, order: 3 @@ -1009,7 +1014,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, { group: '3_directional', command: { id: 'workbench.action.focusBelowGroup', - title: nls.localize({ key: 'miFocusBelowGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Below"), + title: localize({ key: 'miFocusBelowGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Below"), precondition: ContextKeyExpr.has('multipleEditorGroups') }, order: 4 @@ -1017,7 +1022,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, { MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, { group: '2_editor_nav', - title: nls.localize({ key: 'miSwitchGroup', comment: ['&& denotes a mnemonic'] }, "Switch &&Group"), + title: localize({ key: 'miSwitchGroup', comment: ['&& denotes a mnemonic'] }, "Switch &&Group"), submenu: MenuId.MenubarSwitchGroupMenu, order: 2 }); diff --git a/src/vs/workbench/browser/parts/editor/editorActions.ts b/src/vs/workbench/browser/parts/editor/editorActions.ts index db48f417148..df7238d6ef2 100644 --- a/src/vs/workbench/browser/parts/editor/editorActions.ts +++ b/src/vs/workbench/browser/parts/editor/editorActions.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { Action } from 'vs/base/common/actions'; import { IEditorInput, IEditorIdentifier, IEditorCommandsContext, CloseDirection, SaveReason, EditorsOrder, SideBySideEditorInput } from 'vs/workbench/common/editor'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; @@ -79,7 +79,7 @@ export class BaseSplitEditorAction extends Action { export class SplitEditorAction extends BaseSplitEditorAction { static readonly ID = 'workbench.action.splitEditor'; - static readonly LABEL = nls.localize('splitEditor', "Split Editor"); + static readonly LABEL = localize('splitEditor', "Split Editor"); constructor( id: string, @@ -94,7 +94,7 @@ export class SplitEditorAction extends BaseSplitEditorAction { export class SplitEditorOrthogonalAction extends BaseSplitEditorAction { static readonly ID = 'workbench.action.splitEditorOrthogonal'; - static readonly LABEL = nls.localize('splitEditorOrthogonal', "Split Editor Orthogonal"); + static readonly LABEL = localize('splitEditorOrthogonal', "Split Editor Orthogonal"); constructor( id: string, @@ -115,7 +115,7 @@ export class SplitEditorOrthogonalAction extends BaseSplitEditorAction { export class SplitEditorLeftAction extends ExecuteCommandAction { static readonly ID = SPLIT_EDITOR_LEFT; - static readonly LABEL = nls.localize('splitEditorGroupLeft', "Split Editor Left"); + static readonly LABEL = localize('splitEditorGroupLeft', "Split Editor Left"); constructor( id: string, @@ -129,7 +129,7 @@ export class SplitEditorLeftAction extends ExecuteCommandAction { export class SplitEditorRightAction extends ExecuteCommandAction { static readonly ID = SPLIT_EDITOR_RIGHT; - static readonly LABEL = nls.localize('splitEditorGroupRight', "Split Editor Right"); + static readonly LABEL = localize('splitEditorGroupRight', "Split Editor Right"); constructor( id: string, @@ -143,7 +143,7 @@ export class SplitEditorRightAction extends ExecuteCommandAction { export class SplitEditorUpAction extends ExecuteCommandAction { static readonly ID = SPLIT_EDITOR_UP; - static readonly LABEL = nls.localize('splitEditorGroupUp', "Split Editor Up"); + static readonly LABEL = localize('splitEditorGroupUp', "Split Editor Up"); constructor( id: string, @@ -157,7 +157,7 @@ export class SplitEditorUpAction extends ExecuteCommandAction { export class SplitEditorDownAction extends ExecuteCommandAction { static readonly ID = SPLIT_EDITOR_DOWN; - static readonly LABEL = nls.localize('splitEditorGroupDown', "Split Editor Down"); + static readonly LABEL = localize('splitEditorGroupDown', "Split Editor Down"); constructor( id: string, @@ -171,7 +171,7 @@ export class SplitEditorDownAction extends ExecuteCommandAction { export class JoinTwoGroupsAction extends Action { static readonly ID = 'workbench.action.joinTwoGroups'; - static readonly LABEL = nls.localize('joinTwoGroups', "Join Editor Group with Next Group"); + static readonly LABEL = localize('joinTwoGroups', "Join Editor Group with Next Group"); constructor( id: string, @@ -206,7 +206,7 @@ export class JoinTwoGroupsAction extends Action { export class JoinAllGroupsAction extends Action { static readonly ID = 'workbench.action.joinAllGroups'; - static readonly LABEL = nls.localize('joinAllGroups', "Join All Editor Groups"); + static readonly LABEL = localize('joinAllGroups', "Join All Editor Groups"); constructor( id: string, @@ -224,7 +224,7 @@ export class JoinAllGroupsAction extends Action { export class NavigateBetweenGroupsAction extends Action { static readonly ID = 'workbench.action.navigateEditorGroups'; - static readonly LABEL = nls.localize('navigateEditorGroups', "Navigate Between Editor Groups"); + static readonly LABEL = localize('navigateEditorGroups', "Navigate Between Editor Groups"); constructor( id: string, @@ -243,7 +243,7 @@ export class NavigateBetweenGroupsAction extends Action { export class FocusActiveGroupAction extends Action { static readonly ID = 'workbench.action.focusActiveEditorGroup'; - static readonly LABEL = nls.localize('focusActiveEditorGroup', "Focus Active Editor Group"); + static readonly LABEL = localize('focusActiveEditorGroup', "Focus Active Editor Group"); constructor( id: string, @@ -280,7 +280,7 @@ export abstract class BaseFocusGroupAction extends Action { export class FocusFirstGroupAction extends BaseFocusGroupAction { static readonly ID = 'workbench.action.focusFirstEditorGroup'; - static readonly LABEL = nls.localize('focusFirstEditorGroup', "Focus First Editor Group"); + static readonly LABEL = localize('focusFirstEditorGroup', "Focus First Editor Group"); constructor( id: string, @@ -294,7 +294,7 @@ export class FocusFirstGroupAction extends BaseFocusGroupAction { export class FocusLastGroupAction extends BaseFocusGroupAction { static readonly ID = 'workbench.action.focusLastEditorGroup'; - static readonly LABEL = nls.localize('focusLastEditorGroup', "Focus Last Editor Group"); + static readonly LABEL = localize('focusLastEditorGroup', "Focus Last Editor Group"); constructor( id: string, @@ -308,7 +308,7 @@ export class FocusLastGroupAction extends BaseFocusGroupAction { export class FocusNextGroup extends BaseFocusGroupAction { static readonly ID = 'workbench.action.focusNextGroup'; - static readonly LABEL = nls.localize('focusNextGroup', "Focus Next Editor Group"); + static readonly LABEL = localize('focusNextGroup', "Focus Next Editor Group"); constructor( id: string, @@ -322,7 +322,7 @@ export class FocusNextGroup extends BaseFocusGroupAction { export class FocusPreviousGroup extends BaseFocusGroupAction { static readonly ID = 'workbench.action.focusPreviousGroup'; - static readonly LABEL = nls.localize('focusPreviousGroup', "Focus Previous Editor Group"); + static readonly LABEL = localize('focusPreviousGroup', "Focus Previous Editor Group"); constructor( id: string, @@ -336,7 +336,7 @@ export class FocusPreviousGroup extends BaseFocusGroupAction { export class FocusLeftGroup extends BaseFocusGroupAction { static readonly ID = 'workbench.action.focusLeftGroup'; - static readonly LABEL = nls.localize('focusLeftGroup', "Focus Left Editor Group"); + static readonly LABEL = localize('focusLeftGroup', "Focus Left Editor Group"); constructor( id: string, @@ -350,7 +350,7 @@ export class FocusLeftGroup extends BaseFocusGroupAction { export class FocusRightGroup extends BaseFocusGroupAction { static readonly ID = 'workbench.action.focusRightGroup'; - static readonly LABEL = nls.localize('focusRightGroup', "Focus Right Editor Group"); + static readonly LABEL = localize('focusRightGroup', "Focus Right Editor Group"); constructor( id: string, @@ -364,7 +364,7 @@ export class FocusRightGroup extends BaseFocusGroupAction { export class FocusAboveGroup extends BaseFocusGroupAction { static readonly ID = 'workbench.action.focusAboveGroup'; - static readonly LABEL = nls.localize('focusAboveGroup', "Focus Above Editor Group"); + static readonly LABEL = localize('focusAboveGroup', "Focus Above Editor Group"); constructor( id: string, @@ -378,7 +378,7 @@ export class FocusAboveGroup extends BaseFocusGroupAction { export class FocusBelowGroup extends BaseFocusGroupAction { static readonly ID = 'workbench.action.focusBelowGroup'; - static readonly LABEL = nls.localize('focusBelowGroup', "Focus Below Editor Group"); + static readonly LABEL = localize('focusBelowGroup', "Focus Below Editor Group"); constructor( id: string, @@ -392,7 +392,7 @@ export class FocusBelowGroup extends BaseFocusGroupAction { export class CloseEditorAction extends Action { static readonly ID = 'workbench.action.closeActiveEditor'; - static readonly LABEL = nls.localize('closeEditor', "Close Editor"); + static readonly LABEL = localize('closeEditor', "Close Editor"); constructor( id: string, @@ -410,7 +410,7 @@ export class CloseEditorAction extends Action { export class UnpinEditorAction extends Action { static readonly ID = 'workbench.action.unpinActiveEditor'; - static readonly LABEL = nls.localize('unpinEditor', "Unpin Editor"); + static readonly LABEL = localize('unpinEditor', "Unpin Editor"); constructor( id: string, @@ -428,7 +428,7 @@ export class UnpinEditorAction extends Action { export class CloseOneEditorAction extends Action { static readonly ID = 'workbench.action.closeActiveEditor'; - static readonly LABEL = nls.localize('closeOneEditor', "Close"); + static readonly LABEL = localize('closeOneEditor', "Close"); constructor( id: string, @@ -471,7 +471,7 @@ export class CloseOneEditorAction extends Action { export class RevertAndCloseEditorAction extends Action { static readonly ID = 'workbench.action.revertAndCloseActiveEditor'; - static readonly LABEL = nls.localize('revertAndCloseActiveEditor', "Revert and Close Editor"); + static readonly LABEL = localize('revertAndCloseActiveEditor', "Revert and Close Editor"); constructor( id: string, @@ -506,7 +506,7 @@ export class RevertAndCloseEditorAction extends Action { export class CloseLeftEditorsInGroupAction extends Action { static readonly ID = 'workbench.action.closeEditorsToTheLeft'; - static readonly LABEL = nls.localize('closeEditorsToTheLeft', "Close Editors to the Left in Group"); + static readonly LABEL = localize('closeEditorsToTheLeft', "Close Editors to the Left in Group"); constructor( id: string, @@ -649,7 +649,7 @@ abstract class BaseCloseAllAction extends Action { export class CloseAllEditorsAction extends BaseCloseAllAction { static readonly ID = 'workbench.action.closeAllEditors'; - static readonly LABEL = nls.localize('closeAllEditors', "Close All Editors"); + static readonly LABEL = localize('closeAllEditors', "Close All Editors"); constructor( id: string, @@ -675,7 +675,7 @@ export class CloseAllEditorsAction extends BaseCloseAllAction { export class CloseAllEditorGroupsAction extends BaseCloseAllAction { static readonly ID = 'workbench.action.closeAllGroups'; - static readonly LABEL = nls.localize('closeAllGroups', "Close All Editor Groups"); + static readonly LABEL = localize('closeAllGroups', "Close All Editor Groups"); constructor( id: string, @@ -703,7 +703,7 @@ export class CloseAllEditorGroupsAction extends BaseCloseAllAction { export class CloseEditorsInOtherGroupsAction extends Action { static readonly ID = 'workbench.action.closeEditorsInOtherGroups'; - static readonly LABEL = nls.localize('closeEditorsInOtherGroups', "Close Editors in Other Groups"); + static readonly LABEL = localize('closeEditorsInOtherGroups', "Close Editors in Other Groups"); constructor( id: string, @@ -728,7 +728,7 @@ export class CloseEditorsInOtherGroupsAction extends Action { export class CloseEditorInAllGroupsAction extends Action { static readonly ID = 'workbench.action.closeEditorInAllGroups'; - static readonly LABEL = nls.localize('closeEditorInAllGroups', "Close Editor in All Groups"); + static readonly LABEL = localize('closeEditorInAllGroups', "Close Editor in All Groups"); constructor( id: string, @@ -827,7 +827,7 @@ class BaseMoveGroupAction extends BaseMoveCopyGroupAction { export class MoveGroupLeftAction extends BaseMoveGroupAction { static readonly ID = 'workbench.action.moveActiveEditorGroupLeft'; - static readonly LABEL = nls.localize('moveActiveGroupLeft', "Move Editor Group Left"); + static readonly LABEL = localize('moveActiveGroupLeft', "Move Editor Group Left"); constructor( id: string, @@ -841,7 +841,7 @@ export class MoveGroupLeftAction extends BaseMoveGroupAction { export class MoveGroupRightAction extends BaseMoveGroupAction { static readonly ID = 'workbench.action.moveActiveEditorGroupRight'; - static readonly LABEL = nls.localize('moveActiveGroupRight', "Move Editor Group Right"); + static readonly LABEL = localize('moveActiveGroupRight', "Move Editor Group Right"); constructor( id: string, @@ -855,7 +855,7 @@ export class MoveGroupRightAction extends BaseMoveGroupAction { export class MoveGroupUpAction extends BaseMoveGroupAction { static readonly ID = 'workbench.action.moveActiveEditorGroupUp'; - static readonly LABEL = nls.localize('moveActiveGroupUp', "Move Editor Group Up"); + static readonly LABEL = localize('moveActiveGroupUp', "Move Editor Group Up"); constructor( id: string, @@ -869,7 +869,7 @@ export class MoveGroupUpAction extends BaseMoveGroupAction { export class MoveGroupDownAction extends BaseMoveGroupAction { static readonly ID = 'workbench.action.moveActiveEditorGroupDown'; - static readonly LABEL = nls.localize('moveActiveGroupDown', "Move Editor Group Down"); + static readonly LABEL = localize('moveActiveGroupDown', "Move Editor Group Down"); constructor( id: string, @@ -895,7 +895,7 @@ class BaseDuplicateGroupAction extends BaseMoveCopyGroupAction { export class DuplicateGroupLeftAction extends BaseDuplicateGroupAction { static readonly ID = 'workbench.action.duplicateActiveEditorGroupLeft'; - static readonly LABEL = nls.localize('duplicateActiveGroupLeft', "Duplicate Editor Group Left"); + static readonly LABEL = localize('duplicateActiveGroupLeft', "Duplicate Editor Group Left"); constructor( id: string, @@ -909,7 +909,7 @@ export class DuplicateGroupLeftAction extends BaseDuplicateGroupAction { export class DuplicateGroupRightAction extends BaseDuplicateGroupAction { static readonly ID = 'workbench.action.duplicateActiveEditorGroupRight'; - static readonly LABEL = nls.localize('duplicateActiveGroupRight', "Duplicate Editor Group Right"); + static readonly LABEL = localize('duplicateActiveGroupRight', "Duplicate Editor Group Right"); constructor( id: string, @@ -923,7 +923,7 @@ export class DuplicateGroupRightAction extends BaseDuplicateGroupAction { export class DuplicateGroupUpAction extends BaseDuplicateGroupAction { static readonly ID = 'workbench.action.duplicateActiveEditorGroupUp'; - static readonly LABEL = nls.localize('duplicateActiveGroupUp', "Duplicate Editor Group Up"); + static readonly LABEL = localize('duplicateActiveGroupUp', "Duplicate Editor Group Up"); constructor( id: string, @@ -937,7 +937,7 @@ export class DuplicateGroupUpAction extends BaseDuplicateGroupAction { export class DuplicateGroupDownAction extends BaseDuplicateGroupAction { static readonly ID = 'workbench.action.duplicateActiveEditorGroupDown'; - static readonly LABEL = nls.localize('duplicateActiveGroupDown', "Duplicate Editor Group Down"); + static readonly LABEL = localize('duplicateActiveGroupDown', "Duplicate Editor Group Down"); constructor( id: string, @@ -951,7 +951,7 @@ export class DuplicateGroupDownAction extends BaseDuplicateGroupAction { export class MinimizeOtherGroupsAction extends Action { static readonly ID = 'workbench.action.minimizeOtherEditors'; - static readonly LABEL = nls.localize('minimizeOtherEditorGroups', "Maximize Editor Group"); + static readonly LABEL = localize('minimizeOtherEditorGroups', "Maximize Editor Group"); constructor(id: string, label: string, @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService) { super(id, label); @@ -965,7 +965,7 @@ export class MinimizeOtherGroupsAction extends Action { export class ResetGroupSizesAction extends Action { static readonly ID = 'workbench.action.evenEditorWidths'; - static readonly LABEL = nls.localize('evenEditorGroups', "Reset Editor Group Sizes"); + static readonly LABEL = localize('evenEditorGroups', "Reset Editor Group Sizes"); constructor(id: string, label: string, @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService) { super(id, label); @@ -979,7 +979,7 @@ export class ResetGroupSizesAction extends Action { export class ToggleGroupSizesAction extends Action { static readonly ID = 'workbench.action.toggleEditorWidths'; - static readonly LABEL = nls.localize('toggleEditorWidths', "Toggle Editor Group Sizes"); + static readonly LABEL = localize('toggleEditorWidths', "Toggle Editor Group Sizes"); constructor(id: string, label: string, @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService) { super(id, label); @@ -993,7 +993,7 @@ export class ToggleGroupSizesAction extends Action { export class MaximizeGroupAction extends Action { static readonly ID = 'workbench.action.maximizeEditor'; - static readonly LABEL = nls.localize('maximizeEditor', "Maximize Editor Group and Hide Side Bar"); + static readonly LABEL = localize('maximizeEditor', "Maximize Editor Group and Hide Side Bar"); constructor( id: string, @@ -1047,7 +1047,7 @@ export abstract class BaseNavigateEditorAction extends Action { export class OpenNextEditor extends BaseNavigateEditorAction { static readonly ID = 'workbench.action.nextEditor'; - static readonly LABEL = nls.localize('openNextEditor', "Open Next Editor"); + static readonly LABEL = localize('openNextEditor', "Open Next Editor"); constructor( id: string, @@ -1082,7 +1082,7 @@ export class OpenNextEditor extends BaseNavigateEditorAction { export class OpenPreviousEditor extends BaseNavigateEditorAction { static readonly ID = 'workbench.action.previousEditor'; - static readonly LABEL = nls.localize('openPreviousEditor', "Open Previous Editor"); + static readonly LABEL = localize('openPreviousEditor', "Open Previous Editor"); constructor( id: string, @@ -1117,7 +1117,7 @@ export class OpenPreviousEditor extends BaseNavigateEditorAction { export class OpenNextEditorInGroup extends BaseNavigateEditorAction { static readonly ID = 'workbench.action.nextEditorInGroup'; - static readonly LABEL = nls.localize('nextEditorInGroup', "Open Next Editor in Group"); + static readonly LABEL = localize('nextEditorInGroup', "Open Next Editor in Group"); constructor( id: string, @@ -1140,7 +1140,7 @@ export class OpenNextEditorInGroup extends BaseNavigateEditorAction { export class OpenPreviousEditorInGroup extends BaseNavigateEditorAction { static readonly ID = 'workbench.action.previousEditorInGroup'; - static readonly LABEL = nls.localize('openPreviousEditorInGroup', "Open Previous Editor in Group"); + static readonly LABEL = localize('openPreviousEditorInGroup', "Open Previous Editor in Group"); constructor( id: string, @@ -1163,7 +1163,7 @@ export class OpenPreviousEditorInGroup extends BaseNavigateEditorAction { export class OpenFirstEditorInGroup extends BaseNavigateEditorAction { static readonly ID = 'workbench.action.firstEditorInGroup'; - static readonly LABEL = nls.localize('firstEditorInGroup', "Open First Editor in Group"); + static readonly LABEL = localize('firstEditorInGroup', "Open First Editor in Group"); constructor( id: string, @@ -1185,7 +1185,7 @@ export class OpenFirstEditorInGroup extends BaseNavigateEditorAction { export class OpenLastEditorInGroup extends BaseNavigateEditorAction { static readonly ID = 'workbench.action.lastEditorInGroup'; - static readonly LABEL = nls.localize('lastEditorInGroup', "Open Last Editor in Group"); + static readonly LABEL = localize('lastEditorInGroup', "Open Last Editor in Group"); constructor( id: string, @@ -1207,7 +1207,7 @@ export class OpenLastEditorInGroup extends BaseNavigateEditorAction { export class NavigateForwardAction extends Action { static readonly ID = 'workbench.action.navigateForward'; - static readonly LABEL = nls.localize('navigateNext', "Go Forward"); + static readonly LABEL = localize('navigateNext', "Go Forward"); constructor(id: string, label: string, @IHistoryService private readonly historyService: IHistoryService) { super(id, label); @@ -1221,7 +1221,7 @@ export class NavigateForwardAction extends Action { export class NavigateBackwardsAction extends Action { static readonly ID = 'workbench.action.navigateBack'; - static readonly LABEL = nls.localize('navigatePrevious', "Go Back"); + static readonly LABEL = localize('navigatePrevious', "Go Back"); constructor(id: string, label: string, @IHistoryService private readonly historyService: IHistoryService) { super(id, label); @@ -1235,7 +1235,7 @@ export class NavigateBackwardsAction extends Action { export class NavigateToLastEditLocationAction extends Action { static readonly ID = 'workbench.action.navigateToLastEditLocation'; - static readonly LABEL = nls.localize('navigateToLastEditLocation', "Go to Last Edit Location"); + static readonly LABEL = localize('navigateToLastEditLocation', "Go to Last Edit Location"); constructor(id: string, label: string, @IHistoryService private readonly historyService: IHistoryService) { super(id, label); @@ -1249,7 +1249,7 @@ export class NavigateToLastEditLocationAction extends Action { export class NavigateLastAction extends Action { static readonly ID = 'workbench.action.navigateLast'; - static readonly LABEL = nls.localize('navigateLast', "Go Last"); + static readonly LABEL = localize('navigateLast', "Go Last"); constructor(id: string, label: string, @IHistoryService private readonly historyService: IHistoryService) { super(id, label); @@ -1263,7 +1263,7 @@ export class NavigateLastAction extends Action { export class ReopenClosedEditorAction extends Action { static readonly ID = 'workbench.action.reopenClosedEditor'; - static readonly LABEL = nls.localize('reopenClosedEditor', "Reopen Closed Editor"); + static readonly LABEL = localize('reopenClosedEditor', "Reopen Closed Editor"); constructor( id: string, @@ -1281,7 +1281,7 @@ export class ReopenClosedEditorAction extends Action { export class ClearRecentFilesAction extends Action { static readonly ID = 'workbench.action.clearRecentFiles'; - static readonly LABEL = nls.localize('clearRecentFiles', "Clear Recently Opened"); + static readonly LABEL = localize('clearRecentFiles', "Clear Recently Opened"); constructor( id: string, @@ -1305,7 +1305,7 @@ export class ClearRecentFilesAction extends Action { export class ShowEditorsInActiveGroupByMostRecentlyUsedAction extends Action { static readonly ID = 'workbench.action.showEditorsInActiveGroup'; - static readonly LABEL = nls.localize('showEditorsInActiveGroup', "Show Editors in Active Group By Most Recently Used"); + static readonly LABEL = localize('showEditorsInActiveGroup', "Show Editors in Active Group By Most Recently Used"); constructor( id: string, @@ -1323,7 +1323,7 @@ export class ShowEditorsInActiveGroupByMostRecentlyUsedAction extends Action { export class ShowAllEditorsByAppearanceAction extends Action { static readonly ID = 'workbench.action.showAllEditors'; - static readonly LABEL = nls.localize('showAllEditors', "Show All Editors By Appearance"); + static readonly LABEL = localize('showAllEditors', "Show All Editors By Appearance"); constructor( id: string, @@ -1341,7 +1341,7 @@ export class ShowAllEditorsByAppearanceAction extends Action { export class ShowAllEditorsByMostRecentlyUsedAction extends Action { static readonly ID = 'workbench.action.showAllEditorsByMostRecentlyUsed'; - static readonly LABEL = nls.localize('showAllEditorsByMostRecentlyUsed', "Show All Editors By Most Recently Used"); + static readonly LABEL = localize('showAllEditorsByMostRecentlyUsed', "Show All Editors By Most Recently Used"); constructor( id: string, @@ -1382,7 +1382,7 @@ export class BaseQuickAccessEditorAction extends Action { export class QuickAccessPreviousRecentlyUsedEditorAction extends BaseQuickAccessEditorAction { static readonly ID = 'workbench.action.quickOpenPreviousRecentlyUsedEditor'; - static readonly LABEL = nls.localize('quickOpenPreviousRecentlyUsedEditor', "Quick Open Previous Recently Used Editor"); + static readonly LABEL = localize('quickOpenPreviousRecentlyUsedEditor', "Quick Open Previous Recently Used Editor"); constructor( id: string, @@ -1397,7 +1397,7 @@ export class QuickAccessPreviousRecentlyUsedEditorAction extends BaseQuickAccess export class QuickAccessLeastRecentlyUsedEditorAction extends BaseQuickAccessEditorAction { static readonly ID = 'workbench.action.quickOpenLeastRecentlyUsedEditor'; - static readonly LABEL = nls.localize('quickOpenLeastRecentlyUsedEditor', "Quick Open Least Recently Used Editor"); + static readonly LABEL = localize('quickOpenLeastRecentlyUsedEditor', "Quick Open Least Recently Used Editor"); constructor( id: string, @@ -1412,7 +1412,7 @@ export class QuickAccessLeastRecentlyUsedEditorAction extends BaseQuickAccessEdi export class QuickAccessPreviousRecentlyUsedEditorInGroupAction extends BaseQuickAccessEditorAction { static readonly ID = 'workbench.action.quickOpenPreviousRecentlyUsedEditorInGroup'; - static readonly LABEL = nls.localize('quickOpenPreviousRecentlyUsedEditorInGroup', "Quick Open Previous Recently Used Editor in Group"); + static readonly LABEL = localize('quickOpenPreviousRecentlyUsedEditorInGroup', "Quick Open Previous Recently Used Editor in Group"); constructor( id: string, @@ -1427,7 +1427,7 @@ export class QuickAccessPreviousRecentlyUsedEditorInGroupAction extends BaseQuic export class QuickAccessLeastRecentlyUsedEditorInGroupAction extends BaseQuickAccessEditorAction { static readonly ID = 'workbench.action.quickOpenLeastRecentlyUsedEditorInGroup'; - static readonly LABEL = nls.localize('quickOpenLeastRecentlyUsedEditorInGroup', "Quick Open Least Recently Used Editor in Group"); + static readonly LABEL = localize('quickOpenLeastRecentlyUsedEditorInGroup', "Quick Open Least Recently Used Editor in Group"); constructor( id: string, @@ -1442,7 +1442,7 @@ export class QuickAccessLeastRecentlyUsedEditorInGroupAction extends BaseQuickAc export class QuickAccessPreviousEditorFromHistoryAction extends Action { static readonly ID = 'workbench.action.openPreviousEditorFromHistory'; - static readonly LABEL = nls.localize('navigateEditorHistoryByInput', "Quick Open Previous Editor from History"); + static readonly LABEL = localize('navigateEditorHistoryByInput', "Quick Open Previous Editor from History"); constructor( id: string, @@ -1471,7 +1471,7 @@ export class QuickAccessPreviousEditorFromHistoryAction extends Action { export class OpenNextRecentlyUsedEditorAction extends Action { static readonly ID = 'workbench.action.openNextRecentlyUsedEditor'; - static readonly LABEL = nls.localize('openNextRecentlyUsedEditor', "Open Next Recently Used Editor"); + static readonly LABEL = localize('openNextRecentlyUsedEditor', "Open Next Recently Used Editor"); constructor( id: string, @@ -1489,7 +1489,7 @@ export class OpenNextRecentlyUsedEditorAction extends Action { export class OpenPreviousRecentlyUsedEditorAction extends Action { static readonly ID = 'workbench.action.openPreviousRecentlyUsedEditor'; - static readonly LABEL = nls.localize('openPreviousRecentlyUsedEditor', "Open Previous Recently Used Editor"); + static readonly LABEL = localize('openPreviousRecentlyUsedEditor', "Open Previous Recently Used Editor"); constructor( id: string, @@ -1507,7 +1507,7 @@ export class OpenPreviousRecentlyUsedEditorAction extends Action { export class OpenNextRecentlyUsedEditorInGroupAction extends Action { static readonly ID = 'workbench.action.openNextRecentlyUsedEditorInGroup'; - static readonly LABEL = nls.localize('openNextRecentlyUsedEditorInGroup', "Open Next Recently Used Editor In Group"); + static readonly LABEL = localize('openNextRecentlyUsedEditorInGroup', "Open Next Recently Used Editor In Group"); constructor( id: string, @@ -1526,7 +1526,7 @@ export class OpenNextRecentlyUsedEditorInGroupAction extends Action { export class OpenPreviousRecentlyUsedEditorInGroupAction extends Action { static readonly ID = 'workbench.action.openPreviousRecentlyUsedEditorInGroup'; - static readonly LABEL = nls.localize('openPreviousRecentlyUsedEditorInGroup', "Open Previous Recently Used Editor In Group"); + static readonly LABEL = localize('openPreviousRecentlyUsedEditorInGroup', "Open Previous Recently Used Editor In Group"); constructor( id: string, @@ -1545,7 +1545,7 @@ export class OpenPreviousRecentlyUsedEditorInGroupAction extends Action { export class ClearEditorHistoryAction extends Action { static readonly ID = 'workbench.action.clearEditorHistory'; - static readonly LABEL = nls.localize('clearEditorHistory', "Clear Editor History"); + static readonly LABEL = localize('clearEditorHistory', "Clear Editor History"); constructor( id: string, @@ -1565,7 +1565,7 @@ export class ClearEditorHistoryAction extends Action { export class MoveEditorLeftInGroupAction extends ExecuteCommandAction { static readonly ID = 'workbench.action.moveEditorLeftInGroup'; - static readonly LABEL = nls.localize('moveEditorLeft', "Move Editor Left"); + static readonly LABEL = localize('moveEditorLeft', "Move Editor Left"); constructor( id: string, @@ -1579,7 +1579,7 @@ export class MoveEditorLeftInGroupAction extends ExecuteCommandAction { export class MoveEditorRightInGroupAction extends ExecuteCommandAction { static readonly ID = 'workbench.action.moveEditorRightInGroup'; - static readonly LABEL = nls.localize('moveEditorRight', "Move Editor Right"); + static readonly LABEL = localize('moveEditorRight', "Move Editor Right"); constructor( id: string, @@ -1593,7 +1593,7 @@ export class MoveEditorRightInGroupAction extends ExecuteCommandAction { export class MoveEditorToPreviousGroupAction extends ExecuteCommandAction { static readonly ID = 'workbench.action.moveEditorToPreviousGroup'; - static readonly LABEL = nls.localize('moveEditorToPreviousGroup', "Move Editor into Previous Group"); + static readonly LABEL = localize('moveEditorToPreviousGroup', "Move Editor into Previous Group"); constructor( id: string, @@ -1607,7 +1607,7 @@ export class MoveEditorToPreviousGroupAction extends ExecuteCommandAction { export class MoveEditorToNextGroupAction extends ExecuteCommandAction { static readonly ID = 'workbench.action.moveEditorToNextGroup'; - static readonly LABEL = nls.localize('moveEditorToNextGroup', "Move Editor into Next Group"); + static readonly LABEL = localize('moveEditorToNextGroup', "Move Editor into Next Group"); constructor( id: string, @@ -1621,7 +1621,7 @@ export class MoveEditorToNextGroupAction extends ExecuteCommandAction { export class MoveEditorToAboveGroupAction extends ExecuteCommandAction { static readonly ID = 'workbench.action.moveEditorToAboveGroup'; - static readonly LABEL = nls.localize('moveEditorToAboveGroup', "Move Editor into Above Group"); + static readonly LABEL = localize('moveEditorToAboveGroup', "Move Editor into Above Group"); constructor( id: string, @@ -1635,7 +1635,7 @@ export class MoveEditorToAboveGroupAction extends ExecuteCommandAction { export class MoveEditorToBelowGroupAction extends ExecuteCommandAction { static readonly ID = 'workbench.action.moveEditorToBelowGroup'; - static readonly LABEL = nls.localize('moveEditorToBelowGroup', "Move Editor into Below Group"); + static readonly LABEL = localize('moveEditorToBelowGroup', "Move Editor into Below Group"); constructor( id: string, @@ -1649,7 +1649,7 @@ export class MoveEditorToBelowGroupAction extends ExecuteCommandAction { export class MoveEditorToLeftGroupAction extends ExecuteCommandAction { static readonly ID = 'workbench.action.moveEditorToLeftGroup'; - static readonly LABEL = nls.localize('moveEditorToLeftGroup', "Move Editor into Left Group"); + static readonly LABEL = localize('moveEditorToLeftGroup', "Move Editor into Left Group"); constructor( id: string, @@ -1663,7 +1663,7 @@ export class MoveEditorToLeftGroupAction extends ExecuteCommandAction { export class MoveEditorToRightGroupAction extends ExecuteCommandAction { static readonly ID = 'workbench.action.moveEditorToRightGroup'; - static readonly LABEL = nls.localize('moveEditorToRightGroup', "Move Editor into Right Group"); + static readonly LABEL = localize('moveEditorToRightGroup', "Move Editor into Right Group"); constructor( id: string, @@ -1677,7 +1677,7 @@ export class MoveEditorToRightGroupAction extends ExecuteCommandAction { export class MoveEditorToFirstGroupAction extends ExecuteCommandAction { static readonly ID = 'workbench.action.moveEditorToFirstGroup'; - static readonly LABEL = nls.localize('moveEditorToFirstGroup', "Move Editor into First Group"); + static readonly LABEL = localize('moveEditorToFirstGroup', "Move Editor into First Group"); constructor( id: string, @@ -1691,7 +1691,7 @@ export class MoveEditorToFirstGroupAction extends ExecuteCommandAction { export class MoveEditorToLastGroupAction extends ExecuteCommandAction { static readonly ID = 'workbench.action.moveEditorToLastGroup'; - static readonly LABEL = nls.localize('moveEditorToLastGroup', "Move Editor into Last Group"); + static readonly LABEL = localize('moveEditorToLastGroup', "Move Editor into Last Group"); constructor( id: string, @@ -1705,7 +1705,7 @@ export class MoveEditorToLastGroupAction extends ExecuteCommandAction { export class EditorLayoutSingleAction extends ExecuteCommandAction { static readonly ID = 'workbench.action.editorLayoutSingle'; - static readonly LABEL = nls.localize('editorLayoutSingle', "Single Column Editor Layout"); + static readonly LABEL = localize('editorLayoutSingle', "Single Column Editor Layout"); constructor( id: string, @@ -1719,7 +1719,7 @@ export class EditorLayoutSingleAction extends ExecuteCommandAction { export class EditorLayoutTwoColumnsAction extends ExecuteCommandAction { static readonly ID = 'workbench.action.editorLayoutTwoColumns'; - static readonly LABEL = nls.localize('editorLayoutTwoColumns', "Two Columns Editor Layout"); + static readonly LABEL = localize('editorLayoutTwoColumns', "Two Columns Editor Layout"); constructor( id: string, @@ -1733,7 +1733,7 @@ export class EditorLayoutTwoColumnsAction extends ExecuteCommandAction { export class EditorLayoutThreeColumnsAction extends ExecuteCommandAction { static readonly ID = 'workbench.action.editorLayoutThreeColumns'; - static readonly LABEL = nls.localize('editorLayoutThreeColumns', "Three Columns Editor Layout"); + static readonly LABEL = localize('editorLayoutThreeColumns', "Three Columns Editor Layout"); constructor( id: string, @@ -1747,7 +1747,7 @@ export class EditorLayoutThreeColumnsAction extends ExecuteCommandAction { export class EditorLayoutTwoRowsAction extends ExecuteCommandAction { static readonly ID = 'workbench.action.editorLayoutTwoRows'; - static readonly LABEL = nls.localize('editorLayoutTwoRows', "Two Rows Editor Layout"); + static readonly LABEL = localize('editorLayoutTwoRows', "Two Rows Editor Layout"); constructor( id: string, @@ -1761,7 +1761,7 @@ export class EditorLayoutTwoRowsAction extends ExecuteCommandAction { export class EditorLayoutThreeRowsAction extends ExecuteCommandAction { static readonly ID = 'workbench.action.editorLayoutThreeRows'; - static readonly LABEL = nls.localize('editorLayoutThreeRows', "Three Rows Editor Layout"); + static readonly LABEL = localize('editorLayoutThreeRows', "Three Rows Editor Layout"); constructor( id: string, @@ -1775,7 +1775,7 @@ export class EditorLayoutThreeRowsAction extends ExecuteCommandAction { export class EditorLayoutTwoByTwoGridAction extends ExecuteCommandAction { static readonly ID = 'workbench.action.editorLayoutTwoByTwoGrid'; - static readonly LABEL = nls.localize('editorLayoutTwoByTwoGrid', "Grid Editor Layout (2x2)"); + static readonly LABEL = localize('editorLayoutTwoByTwoGrid', "Grid Editor Layout (2x2)"); constructor( id: string, @@ -1789,7 +1789,7 @@ export class EditorLayoutTwoByTwoGridAction extends ExecuteCommandAction { export class EditorLayoutTwoColumnsBottomAction extends ExecuteCommandAction { static readonly ID = 'workbench.action.editorLayoutTwoColumnsBottom'; - static readonly LABEL = nls.localize('editorLayoutTwoColumnsBottom', "Two Columns Bottom Editor Layout"); + static readonly LABEL = localize('editorLayoutTwoColumnsBottom', "Two Columns Bottom Editor Layout"); constructor( id: string, @@ -1803,7 +1803,7 @@ export class EditorLayoutTwoColumnsBottomAction extends ExecuteCommandAction { export class EditorLayoutTwoRowsRightAction extends ExecuteCommandAction { static readonly ID = 'workbench.action.editorLayoutTwoRowsRight'; - static readonly LABEL = nls.localize('editorLayoutTwoRowsRight', "Two Rows Right Editor Layout"); + static readonly LABEL = localize('editorLayoutTwoRowsRight', "Two Rows Right Editor Layout"); constructor( id: string, @@ -1833,7 +1833,7 @@ export class BaseCreateEditorGroupAction extends Action { export class NewEditorGroupLeftAction extends BaseCreateEditorGroupAction { static readonly ID = 'workbench.action.newGroupLeft'; - static readonly LABEL = nls.localize('newEditorLeft', "New Editor Group to the Left"); + static readonly LABEL = localize('newEditorLeft', "New Editor Group to the Left"); constructor( id: string, @@ -1847,7 +1847,7 @@ export class NewEditorGroupLeftAction extends BaseCreateEditorGroupAction { export class NewEditorGroupRightAction extends BaseCreateEditorGroupAction { static readonly ID = 'workbench.action.newGroupRight'; - static readonly LABEL = nls.localize('newEditorRight', "New Editor Group to the Right"); + static readonly LABEL = localize('newEditorRight', "New Editor Group to the Right"); constructor( id: string, @@ -1861,7 +1861,7 @@ export class NewEditorGroupRightAction extends BaseCreateEditorGroupAction { export class NewEditorGroupAboveAction extends BaseCreateEditorGroupAction { static readonly ID = 'workbench.action.newGroupAbove'; - static readonly LABEL = nls.localize('newEditorAbove', "New Editor Group Above"); + static readonly LABEL = localize('newEditorAbove', "New Editor Group Above"); constructor( id: string, @@ -1875,7 +1875,7 @@ export class NewEditorGroupAboveAction extends BaseCreateEditorGroupAction { export class NewEditorGroupBelowAction extends BaseCreateEditorGroupAction { static readonly ID = 'workbench.action.newGroupBelow'; - static readonly LABEL = nls.localize('newEditorBelow', "New Editor Group Below"); + static readonly LABEL = localize('newEditorBelow', "New Editor Group Below"); constructor( id: string, @@ -1889,7 +1889,7 @@ export class NewEditorGroupBelowAction extends BaseCreateEditorGroupAction { export class ReopenResourcesAction extends Action { static readonly ID = 'workbench.action.reopenWithEditor'; - static readonly LABEL = nls.localize('workbench.action.reopenWithEditor', "Reopen Editor With..."); + static readonly LABEL = localize('workbench.action.reopenWithEditor', "Reopen Editor With..."); constructor( id: string, @@ -1920,7 +1920,7 @@ export class ReopenResourcesAction extends Action { export class ToggleEditorTypeAction extends Action { static readonly ID = 'workbench.action.toggleEditorType'; - static readonly LABEL = nls.localize('workbench.action.toggleEditorType', "Toggle Editor Type"); + static readonly LABEL = localize('workbench.action.toggleEditorType', "Toggle Editor Type"); constructor( id: string, diff --git a/src/vs/workbench/browser/parts/editor/editorCommands.ts b/src/vs/workbench/browser/parts/editor/editorCommands.ts index f9fd2d57164..1bf46e607df 100644 --- a/src/vs/workbench/browser/parts/editor/editorCommands.ts +++ b/src/vs/workbench/browser/parts/editor/editorCommands.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { isObject, isString, isUndefined, isNumber, withNullAsUndefined } from 'vs/base/common/types'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -103,11 +103,11 @@ function registerActiveEditorMoveCommand(): void { primary: 0, handler: (accessor, args) => moveActiveEditor(args, accessor), description: { - description: nls.localize('editorCommand.activeEditorMove.description', "Move the active editor by tabs or groups"), + description: localize('editorCommand.activeEditorMove.description', "Move the active editor by tabs or groups"), args: [ { - name: nls.localize('editorCommand.activeEditorMove.arg.name', "Active editor move argument"), - description: nls.localize('editorCommand.activeEditorMove.arg.description', "Argument Properties:\n\t* 'to': String value providing where to move.\n\t* 'by': String value providing the unit for move (by tab or by group).\n\t* 'value': Number value providing how many positions or an absolute position to move."), + name: localize('editorCommand.activeEditorMove.arg.name', "Active editor move argument"), + description: localize('editorCommand.activeEditorMove.arg.description', "Argument Properties:\n\t* 'to': String value providing where to move.\n\t* 'by': String value providing the unit for move (by tab or by group).\n\t* 'value': Number value providing how many positions or an absolute position to move."), constraint: isActiveEditorMoveArg, schema: { 'type': 'object', @@ -408,10 +408,10 @@ function registerDiffEditorCommands(): void { command: { id: TOGGLE_DIFF_SIDE_BY_SIDE, title: { - value: nls.localize('toggleInlineView', "Toggle Inline View"), + value: localize('toggleInlineView', "Toggle Inline View"), original: 'Compare: Toggle Inline View' }, - category: nls.localize('compare', "Compare") + category: localize('compare', "Compare") }, when: ContextKeyExpr.has('textCompareEditorActive') }); diff --git a/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts index 90d33b124a2..efd6650f5be 100644 --- a/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts +++ b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as DOM from 'vs/base/browser/dom'; +import { Dimension, $, clearNode } from 'vs/base/browser/dom'; import { Registry } from 'vs/platform/registry/common/platform'; import { EditorInput, EditorOptions, SideBySideEditorInput, IEditorControl, IEditorPane, IEditorOpenContext } from 'vs/workbench/common/editor'; import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; @@ -51,7 +51,7 @@ export class SideBySideEditor extends EditorPane { private secondaryEditorContainer: HTMLElement | undefined; private splitview: SplitView | undefined; - private dimension: DOM.Dimension = new DOM.Dimension(0, 0); + private dimension: Dimension = new Dimension(0, 0); private onDidCreateEditors = this._register(new Emitter<{ width: number; height: number; } | undefined>()); @@ -73,19 +73,19 @@ export class SideBySideEditor extends EditorPane { const splitview = this.splitview = this._register(new SplitView(parent, { orientation: Orientation.HORIZONTAL })); this._register(this.splitview.onDidSashReset(() => splitview.distributeViewSizes())); - this.secondaryEditorContainer = DOM.$('.secondary-editor-container'); + this.secondaryEditorContainer = $('.secondary-editor-container'); this.splitview.addView({ element: this.secondaryEditorContainer, - layout: size => this.secondaryEditorPane?.layout(new DOM.Dimension(size, this.dimension.height)), + layout: size => this.secondaryEditorPane?.layout(new Dimension(size, this.dimension.height)), minimumSize: 220, maximumSize: Number.POSITIVE_INFINITY, onDidChange: Event.None }, Sizing.Distribute); - this.primaryEditorContainer = DOM.$('.primary-editor-container'); + this.primaryEditorContainer = $('.primary-editor-container'); this.splitview.addView({ element: this.primaryEditorContainer, - layout: size => this.primaryEditorPane?.layout(new DOM.Dimension(size, this.dimension.height)), + layout: size => this.primaryEditorPane?.layout(new Dimension(size, this.dimension.height)), minimumSize: 220, maximumSize: Number.POSITIVE_INFINITY, onDidChange: Event.None @@ -139,7 +139,7 @@ export class SideBySideEditor extends EditorPane { } } - layout(dimension: DOM.Dimension): void { + layout(dimension: Dimension): void { this.dimension = dimension; const splitview = assertIsDefined(this.splitview); @@ -238,11 +238,11 @@ export class SideBySideEditor extends EditorPane { } if (this.secondaryEditorContainer) { - DOM.clearNode(this.secondaryEditorContainer); + clearNode(this.secondaryEditorContainer); } if (this.primaryEditorContainer) { - DOM.clearNode(this.primaryEditorContainer); + clearNode(this.primaryEditorContainer); } } diff --git a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts index 7ae3677e182..54eca9b3349 100644 --- a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; -import * as objects from 'vs/base/common/objects'; +import { localize } from 'vs/nls'; +import { deepClone } from 'vs/base/common/objects'; import { isFunction, isObject, isArray, assertIsDefined, withUndefinedAsNull } from 'vs/base/common/types'; import { IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { IDiffEditorOptions, IEditorOptions as ICodeEditorOptions } from 'vs/editor/common/config/editorOptions'; @@ -99,7 +99,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan return this.input.getName(); } - return nls.localize('textDiffEditor', "Text Diff Editor"); + return localize('textDiffEditor', "Text Diff Editor"); } createEditorControl(parent: HTMLElement, configuration: ICodeEditorOptions): IDiffEditor { @@ -236,7 +236,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan // Handle diff editor specially by merging in diffEditor configuration if (isObject(configuration.diffEditor)) { - const diffEditorConfiguration = objects.deepClone(configuration.diffEditor); + const diffEditorConfiguration: IDiffEditorOptions = deepClone(configuration.diffEditor); // User settings defines `diffEditor.codeLens`, but here we rename that to `diffEditor.diffCodeLens` to avoid collisions with `editor.codeLens`. diffEditorConfiguration.diffCodeLens = diffEditorConfiguration.codeLens; diff --git a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts index 2bb2640dc79..63135239171 100644 --- a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { assertIsDefined, isFunction, withNullAsUndefined } from 'vs/base/common/types'; import { ICodeEditor, getCodeEditor, IPasteEvent } from 'vs/editor/browser/editorBrowser'; import { TextEditorOptions, EditorInput, EditorOptions, IEditorOpenContext } from 'vs/workbench/common/editor'; @@ -50,7 +50,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor { return this.input.getName(); } - return nls.localize('textEditor', "Text Editor"); + return localize('textEditor', "Text Editor"); } async setInput(input: EditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { diff --git a/src/vs/workbench/browser/parts/panel/panelActions.ts b/src/vs/workbench/browser/parts/panel/panelActions.ts index 372e78f8a50..0d447ee9d3d 100644 --- a/src/vs/workbench/browser/parts/panel/panelActions.ts +++ b/src/vs/workbench/browser/parts/panel/panelActions.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/panelpart'; -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { Action } from 'vs/base/common/actions'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -21,14 +21,14 @@ import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { ViewContainerLocationToString, ViewContainerLocation } from 'vs/workbench/common/views'; -const maximizeIcon = registerIcon('panel-maximize', Codicon.chevronUp, nls.localize('maximizeIcon', 'Icon to maximize a panel.')); -const restoreIcon = registerIcon('panel-restore', Codicon.chevronDown, nls.localize('restoreIcon', 'Icon to restore a panel.')); -const closeIcon = registerIcon('panel-close', Codicon.close, nls.localize('closeIcon', 'Icon to close a panel.')); +const maximizeIcon = registerIcon('panel-maximize', Codicon.chevronUp, localize('maximizeIcon', 'Icon to maximize a panel.')); +const restoreIcon = registerIcon('panel-restore', Codicon.chevronDown, localize('restoreIcon', 'Icon to restore a panel.')); +const closeIcon = registerIcon('panel-close', Codicon.close, localize('closeIcon', 'Icon to close a panel.')); export class TogglePanelAction extends Action { static readonly ID = 'workbench.action.togglePanel'; - static readonly LABEL = nls.localize('togglePanel', "Toggle Panel"); + static readonly LABEL = localize('togglePanel', "Toggle Panel"); constructor( id: string, @@ -46,7 +46,7 @@ export class TogglePanelAction extends Action { class FocusPanelAction extends Action { static readonly ID = 'workbench.action.focusPanel'; - static readonly LABEL = nls.localize('focusPanel', "Focus into Panel"); + static readonly LABEL = localize('focusPanel', "Focus into Panel"); constructor( id: string, @@ -97,9 +97,9 @@ function createPositionPanelActionConfig(id: string, alias: string, label: strin } export const PositionPanelActionConfigs: PanelActionConfig[] = [ - createPositionPanelActionConfig(PositionPanelActionId.LEFT, 'View: Move Panel Left', nls.localize('positionPanelLeft', 'Move Panel Left'), Position.LEFT), - createPositionPanelActionConfig(PositionPanelActionId.RIGHT, 'View: Move Panel Right', nls.localize('positionPanelRight', 'Move Panel Right'), Position.RIGHT), - createPositionPanelActionConfig(PositionPanelActionId.BOTTOM, 'View: Move Panel To Bottom', nls.localize('positionPanelBottom', 'Move Panel To Bottom'), Position.BOTTOM), + createPositionPanelActionConfig(PositionPanelActionId.LEFT, 'View: Move Panel Left', localize('positionPanelLeft', 'Move Panel Left'), Position.LEFT), + createPositionPanelActionConfig(PositionPanelActionId.RIGHT, 'View: Move Panel Right', localize('positionPanelRight', 'Move Panel Right'), Position.RIGHT), + createPositionPanelActionConfig(PositionPanelActionId.BOTTOM, 'View: Move Panel To Bottom', localize('positionPanelBottom', 'Move Panel To Bottom'), Position.BOTTOM), ]; const positionByActionId = new Map(PositionPanelActionConfigs.map(config => [config.id, config.value])); @@ -191,7 +191,7 @@ export class SwitchPanelViewAction extends Action { export class PreviousPanelViewAction extends SwitchPanelViewAction { static readonly ID = 'workbench.action.previousPanelView'; - static readonly LABEL = nls.localize('previousPanelView', 'Previous Panel View'); + static readonly LABEL = localize('previousPanelView', 'Previous Panel View'); constructor( id: string, @@ -209,7 +209,7 @@ export class PreviousPanelViewAction extends SwitchPanelViewAction { export class NextPanelViewAction extends SwitchPanelViewAction { static readonly ID = 'workbench.action.nextPanelView'; - static readonly LABEL = nls.localize('nextPanelView', 'Next Panel View'); + static readonly LABEL = localize('nextPanelView', 'Next Panel View'); constructor( id: string, @@ -234,12 +234,12 @@ registerAction2(class extends Action2 { constructor() { super({ id: 'workbench.action.toggleMaximizedPanel', - title: { value: nls.localize('toggleMaximizedPanel', "Toggle Maximized Panel"), original: 'Toggle Maximized Panel' }, - tooltip: nls.localize('maximizePanel', "Maximize Panel Size"), + title: { value: localize('toggleMaximizedPanel', "Toggle Maximized Panel"), original: 'Toggle Maximized Panel' }, + tooltip: localize('maximizePanel', "Maximize Panel Size"), category: CATEGORIES.View, f1: true, icon: maximizeIcon, - toggled: { condition: PanelMaximizedContext, icon: restoreIcon, tooltip: nls.localize('minimizePanel', "Restore Panel Size") }, + toggled: { condition: PanelMaximizedContext, icon: restoreIcon, tooltip: localize('minimizePanel', "Restore Panel Size") }, menu: [{ id: MenuId.PanelTitle, group: 'navigation', @@ -266,7 +266,7 @@ registerAction2(class extends Action2 { constructor() { super({ id: 'workbench.action.closePanel', - title: { value: nls.localize('closePanel', "Close Panel"), original: 'Close Panel' }, + title: { value: localize('closePanel', "Close Panel"), original: 'Close Panel' }, category: CATEGORIES.View, icon: closeIcon, menu: [{ @@ -291,7 +291,7 @@ MenuRegistry.appendMenuItems([ group: '2_workbench_layout', command: { id: TogglePanelAction.ID, - title: nls.localize({ key: 'miShowPanel', comment: ['&& denotes a mnemonic'] }, "Show &&Panel"), + title: localize({ key: 'miShowPanel', comment: ['&& denotes a mnemonic'] }, "Show &&Panel"), toggled: ActivePanelContext }, order: 5 @@ -302,7 +302,7 @@ MenuRegistry.appendMenuItems([ group: '3_workbench_layout_move', command: { id: TogglePanelAction.ID, - title: { value: nls.localize('hidePanel', "Hide Panel"), original: 'Hide Panel' }, + title: { value: localize('hidePanel', "Hide Panel"), original: 'Hide Panel' }, }, when: ContextKeyExpr.and(PanelVisibleContext, ContextKeyExpr.equals('viewLocation', ViewContainerLocationToString(ViewContainerLocation.Panel))), order: 2 diff --git a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts index 671a05822eb..ed77ad7b157 100644 --- a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts +++ b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/sidebarpart'; -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; import { CompositePart } from 'vs/workbench/browser/parts/compositePart'; import { Viewlet, ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; @@ -307,7 +307,7 @@ class FocusSideBarAction extends Action2 { constructor() { super({ id: 'workbench.action.focusSideBar', - title: { value: nls.localize('focusSideBar', "Focus into Side Bar"), original: 'Focus into Side Bar' }, + title: { value: localize('focusSideBar', "Focus into Side Bar"), original: 'Focus into Side Bar' }, category: CATEGORIES.View, f1: true, keybinding: { diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts index aa9d9f05f9a..b339140fdd9 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/statusbarpart'; -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { dispose, IDisposable, Disposable, toDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { SimpleIconLabel } from 'vs/base/browser/ui/iconLabel/simpleIconLabel'; @@ -364,7 +364,7 @@ class ToggleStatusbarEntryVisibilityAction extends Action { class HideStatusbarEntryAction extends Action { constructor(id: string, name: string, private model: StatusbarViewModel) { - super(id, nls.localize('hide', "Hide '{0}'", name), undefined, true); + super(id, localize('hide', "Hide '{0}'", name), undefined, true); } async run(): Promise { @@ -613,7 +613,7 @@ export class StatusbarPart extends Part implements IStatusbarService { const actions: IAction[] = []; // Provide an action to hide the status bar at last - actions.push(this.instantiationService.createInstance(ToggleStatusbarVisibilityAction, ToggleStatusbarVisibilityAction.ID, nls.localize('hideStatusBar', "Hide Status Bar"))); + actions.push(this.instantiationService.createInstance(ToggleStatusbarVisibilityAction, ToggleStatusbarVisibilityAction.ID, localize('hideStatusBar', "Hide Status Bar"))); actions.push(new Separator()); // Show an entry per known status entry diff --git a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts index 96f49a70965..0600e3ae769 100644 --- a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts +++ b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts @@ -3,13 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { IMenuService, MenuId, IMenu, SubmenuItemAction, registerAction2, Action2, MenuItemAction } from 'vs/platform/actions/common/actions'; import { registerThemingParticipant, IThemeService } from 'vs/platform/theme/common/themeService'; import { MenuBarVisibility, getTitleBarStyle, IWindowOpenable, getMenuBarVisibility } from 'vs/platform/windows/common/windows'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IAction, Action, SubmenuAction, Separator } from 'vs/base/common/actions'; -import * as DOM from 'vs/base/browser/dom'; +import { addDisposableListener, Dimension, EventType } from 'vs/base/browser/dom'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { isMacintosh, isWeb, isIOS, isNative } from 'vs/base/common/platform'; import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; @@ -63,14 +63,14 @@ export abstract class MenubarControl extends Disposable { }; protected topLevelTitles: { [menu: string]: string } = { - 'File': nls.localize({ key: 'mFile', comment: ['&& denotes a mnemonic'] }, "&&File"), - 'Edit': nls.localize({ key: 'mEdit', comment: ['&& denotes a mnemonic'] }, "&&Edit"), - 'Selection': nls.localize({ key: 'mSelection', comment: ['&& denotes a mnemonic'] }, "&&Selection"), - 'View': nls.localize({ key: 'mView', comment: ['&& denotes a mnemonic'] }, "&&View"), - 'Go': nls.localize({ key: 'mGoto', comment: ['&& denotes a mnemonic'] }, "&&Go"), - 'Run': nls.localize({ key: 'mRun', comment: ['&& denotes a mnemonic'] }, "&&Run"), - 'Terminal': nls.localize({ key: 'mTerminal', comment: ['&& denotes a mnemonic'] }, "&&Terminal"), - 'Help': nls.localize({ key: 'mHelp', comment: ['&& denotes a mnemonic'] }, "&&Help") + 'File': localize({ key: 'mFile', comment: ['&& denotes a mnemonic'] }, "&&File"), + 'Edit': localize({ key: 'mEdit', comment: ['&& denotes a mnemonic'] }, "&&Edit"), + 'Selection': localize({ key: 'mSelection', comment: ['&& denotes a mnemonic'] }, "&&Selection"), + 'View': localize({ key: 'mView', comment: ['&& denotes a mnemonic'] }, "&&View"), + 'Go': localize({ key: 'mGoto', comment: ['&& denotes a mnemonic'] }, "&&Go"), + 'Run': localize({ key: 'mRun', comment: ['&& denotes a mnemonic'] }, "&&Run"), + 'Terminal': localize({ key: 'mTerminal', comment: ['&& denotes a mnemonic'] }, "&&Terminal"), + 'Help': localize({ key: 'mHelp', comment: ['&& denotes a mnemonic'] }, "&&Help") }; protected recentlyOpened: IRecentlyOpened = { files: [], workspaces: [] }; @@ -271,10 +271,10 @@ export abstract class MenubarControl extends Disposable { return; } - const message = nls.localize('menubar.customTitlebarAccessibilityNotification', "Accessibility support is enabled for you. For the most accessible experience, we recommend the custom title bar style."); + const message = localize('menubar.customTitlebarAccessibilityNotification', "Accessibility support is enabled for you. For the most accessible experience, we recommend the custom title bar style."); this.notificationService.prompt(Severity.Info, message, [ { - label: nls.localize('goToSetting', "Open Settings"), + label: localize('goToSetting', "Open Settings"), run: () => { return this.preferencesService.openGlobalSettings(undefined, { query: 'window.titleBarStyle' }); } @@ -432,7 +432,7 @@ export class CustomMenubarControl extends MenubarControl { constructor() { super({ id: `workbench.actions.menubar.focus`, - title: { value: nls.localize('focusMenu', "Focus Application Menu"), original: 'Focus Application Menu' }, + title: { value: localize('focusMenu', "Focus Application Menu"), original: 'Focus Application Menu' }, keybinding: { primary: KeyCode.F10, weight: KeybindingWeight.WorkbenchContrib, @@ -459,28 +459,28 @@ export class CustomMenubarControl extends MenubarControl { return null; case StateType.Idle: - return new Action('update.check', nls.localize({ key: 'checkForUpdates', comment: ['&& denotes a mnemonic'] }, "Check for &&Updates..."), undefined, true, () => + return new Action('update.check', localize({ key: 'checkForUpdates', comment: ['&& denotes a mnemonic'] }, "Check for &&Updates..."), undefined, true, () => this.updateService.checkForUpdates(this.environmentService.sessionId)); case StateType.CheckingForUpdates: - return new Action('update.checking', nls.localize('checkingForUpdates', "Checking for Updates..."), undefined, false); + return new Action('update.checking', localize('checkingForUpdates', "Checking for Updates..."), undefined, false); case StateType.AvailableForDownload: - return new Action('update.downloadNow', nls.localize({ key: 'download now', comment: ['&& denotes a mnemonic'] }, "D&&ownload Update"), undefined, true, () => + return new Action('update.downloadNow', localize({ key: 'download now', comment: ['&& denotes a mnemonic'] }, "D&&ownload Update"), undefined, true, () => this.updateService.downloadUpdate()); case StateType.Downloading: - return new Action('update.downloading', nls.localize('DownloadingUpdate', "Downloading Update..."), undefined, false); + return new Action('update.downloading', localize('DownloadingUpdate', "Downloading Update..."), undefined, false); case StateType.Downloaded: - return new Action('update.install', nls.localize({ key: 'installUpdate...', comment: ['&& denotes a mnemonic'] }, "Install &&Update..."), undefined, true, () => + return new Action('update.install', localize({ key: 'installUpdate...', comment: ['&& denotes a mnemonic'] }, "Install &&Update..."), undefined, true, () => this.updateService.applyUpdate()); case StateType.Updating: - return new Action('update.updating', nls.localize('installingUpdate', "Installing Update..."), undefined, false); + return new Action('update.updating', localize('installingUpdate', "Installing Update..."), undefined, false); case StateType.Ready: - return new Action('update.restart', nls.localize({ key: 'restartToUpdate', comment: ['&& denotes a mnemonic'] }, "Restart to &&Update"), undefined, true, () => + return new Action('update.restart', localize({ key: 'restartToUpdate', comment: ['&& denotes a mnemonic'] }, "Restart to &&Update"), undefined, true, () => this.updateService.quitAndInstall()); } } @@ -574,11 +574,11 @@ export class CustomMenubarControl extends MenubarControl { this._register(this.menubar.onVisibilityChange(e => this.onDidVisibilityChange(e))); // Before we focus the menubar, stop updates to it so that focus-related context keys will work - this._register(DOM.addDisposableListener(this.container, DOM.EventType.FOCUS_IN, () => { + this._register(addDisposableListener(this.container, EventType.FOCUS_IN, () => { this.focusInsideMenubar = true; })); - this._register(DOM.addDisposableListener(this.container, DOM.EventType.FOCUS_OUT, () => { + this._register(addDisposableListener(this.container, EventType.FOCUS_OUT, () => { this.focusInsideMenubar = false; })); @@ -722,7 +722,7 @@ export class CustomMenubarControl extends MenubarControl { const webNavigationActions: IAction[] = []; const href = this.environmentService.options?.homeIndicator?.href; if (href) { - webNavigationActions.push(new Action('goHome', nls.localize('goHome', "Go Home"), undefined, true, + webNavigationActions.push(new Action('goHome', localize('goHome', "Go Home"), undefined, true, async (event?: MouseEvent) => { if ((!isMacintosh && event?.ctrlKey) || (isMacintosh && event?.metaKey)) { window.open(href, '_blank'); @@ -784,7 +784,7 @@ export class CustomMenubarControl extends MenubarControl { protected registerListeners(): void { super.registerListeners(); - this._register(DOM.addDisposableListener(window, DOM.EventType.RESIZE, () => { + this._register(addDisposableListener(window, EventType.RESIZE, () => { if (this.menubar && !(isIOS && BrowserFeatures.pointerEvents)) { this.menubar.blur(); } @@ -805,12 +805,12 @@ export class CustomMenubarControl extends MenubarControl { return this._onFocusStateChange.event; } - getMenubarItemsDimensions(): DOM.Dimension { + getMenubarItemsDimensions(): Dimension { if (this.menubar) { - return new DOM.Dimension(this.menubar.getWidth(), this.menubar.getHeight()); + return new Dimension(this.menubar.getWidth(), this.menubar.getHeight()); } - return new DOM.Dimension(0, 0); + return new Dimension(0, 0); } create(parent: HTMLElement): HTMLElement { @@ -824,7 +824,7 @@ export class CustomMenubarControl extends MenubarControl { return this.container; } - layout(dimension: DOM.Dimension) { + layout(dimension: Dimension) { if (this.container) { this.container.style.height = `${dimension.height}px`; } diff --git a/src/vs/workbench/browser/style.ts b/src/vs/workbench/browser/style.ts index 4f1ecbcd076..5028f89cc5a 100644 --- a/src/vs/workbench/browser/style.ts +++ b/src/vs/workbench/browser/style.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/style'; - import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { iconForeground, foreground, selectionBackground, focusBorder, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, listHighlightForeground, inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry'; import { WORKBENCH_BACKGROUND, TITLE_BAR_ACTIVE_BACKGROUND } from 'vs/workbench/common/theme'; diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts index e1353541362..99f76cbf138 100644 --- a/src/vs/workbench/browser/workbench.contribution.ts +++ b/src/vs/workbench/browser/workbench.contribution.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Registry } from 'vs/platform/registry/common/platform'; -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { isMacintosh, isWindows, isLinux, isWeb, isNative } from 'vs/base/common/platform'; import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration'; @@ -22,53 +22,53 @@ import { isStandalone } from 'vs/base/browser/browser'; type: 'string', enum: ['default', 'large'], enumDescriptions: [ - nls.localize('workbench.editor.titleScrollbarSizing.default', "The default size."), - nls.localize('workbench.editor.titleScrollbarSizing.large', "Increases the size, so it can be grabbed more easily with the mouse") + localize('workbench.editor.titleScrollbarSizing.default', "The default size."), + localize('workbench.editor.titleScrollbarSizing.large', "Increases the size, so it can be grabbed more easily with the mouse") ], - description: nls.localize('tabScrollbarHeight', "Controls the height of the scrollbars used for tabs and breadcrumbs in the editor title area."), + description: localize('tabScrollbarHeight', "Controls the height of the scrollbars used for tabs and breadcrumbs in the editor title area."), default: 'default', }, 'workbench.editor.showTabs': { 'type': 'boolean', - 'description': nls.localize('showEditorTabs', "Controls whether opened editors should show in tabs or not."), + 'description': localize('showEditorTabs', "Controls whether opened editors should show in tabs or not."), 'default': true }, 'workbench.editor.wrapTabs': { 'type': 'boolean', - 'markdownDescription': nls.localize('wrapTabs', "Controls whether tabs should be wrapped over multiple lines when exceeding available space or whether a scrollbar should appear instead. This value is ignored when `#workbench.editor.showTabs#` is disabled."), + 'markdownDescription': localize('wrapTabs', "Controls whether tabs should be wrapped over multiple lines when exceeding available space or whether a scrollbar should appear instead. This value is ignored when `#workbench.editor.showTabs#` is disabled."), 'default': false }, 'workbench.editor.scrollToSwitchTabs': { 'type': 'boolean', - 'markdownDescription': 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. This value is ignored when `#workbench.editor.showTabs#` is disabled."), + 'markdownDescription': 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. This value is ignored when `#workbench.editor.showTabs#` is disabled."), 'default': false }, 'workbench.editor.highlightModifiedTabs': { 'type': 'boolean', - 'markdownDescription': nls.localize('highlightModifiedTabs', "Controls whether a top border is drawn on modified (dirty) editor tabs or not. This value is ignored when `#workbench.editor.showTabs#` is disabled."), + 'markdownDescription': localize('highlightModifiedTabs', "Controls whether a top border is drawn on modified (dirty) editor tabs or not. This value is ignored when `#workbench.editor.showTabs#` is disabled."), 'default': false }, 'workbench.editor.decorations.badges': { 'type': 'boolean', - 'markdownDescription': nls.localize('decorations.badges', "Controls whether editor file decorations should use badges."), + 'markdownDescription': localize('decorations.badges', "Controls whether editor file decorations should use badges."), 'default': false }, 'workbench.editor.decorations.colors': { 'type': 'boolean', - 'markdownDescription': nls.localize('decorations.colors', "Controls whether editor file decorations should use colors."), + 'markdownDescription': localize('decorations.colors', "Controls whether editor file decorations should use colors."), 'default': false }, 'workbench.editor.labelFormat': { 'type': 'string', 'enum': ['default', 'short', 'medium', 'long'], 'enumDescriptions': [ - nls.localize('workbench.editor.labelFormat.default', "Show the name of the file. When tabs are enabled and two files have the same name in one group the distinguishing sections of each file's path are added. When tabs are disabled, the path relative to the workspace folder is shown if the editor is active."), - nls.localize('workbench.editor.labelFormat.short', "Show the name of the file followed by its directory name."), - nls.localize('workbench.editor.labelFormat.medium', "Show the name of the file followed by its path relative to the workspace folder."), - nls.localize('workbench.editor.labelFormat.long', "Show the name of the file followed by its absolute path.") + localize('workbench.editor.labelFormat.default', "Show the name of the file. When tabs are enabled and two files have the same name in one group the distinguishing sections of each file's path are added. When tabs are disabled, the path relative to the workspace folder is shown if the editor is active."), + localize('workbench.editor.labelFormat.short', "Show the name of the file followed by its directory name."), + localize('workbench.editor.labelFormat.medium', "Show the name of the file followed by its path relative to the workspace folder."), + localize('workbench.editor.labelFormat.long', "Show the name of the file followed by its absolute path.") ], 'default': 'default', - 'description': nls.localize({ + 'description': localize({ comment: ['This is the description for a setting. Values surrounded by parenthesis are not to be translated.'], key: 'tabDescription' }, "Controls the format of the label for an editor."), @@ -77,11 +77,11 @@ import { isStandalone } from 'vs/base/browser/browser'; '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."), + 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."), + 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({ + 'description': 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."), @@ -90,222 +90,222 @@ import { isStandalone } from 'vs/base/browser/browser'; 'type': 'string', 'enum': ['left', 'right', 'off'], 'default': 'right', - 'markdownDescription': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'editorTabCloseButton' }, "Controls the position of the editor's tabs close buttons, or disables them when set to 'off'. This value is ignored when `#workbench.editor.showTabs#` is disabled.") + 'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'editorTabCloseButton' }, "Controls the position of the editor's tabs close buttons, or disables them when set to 'off'. This value is ignored when `#workbench.editor.showTabs#` is disabled.") }, 'workbench.editor.tabSizing': { 'type': 'string', 'enum': ['fit', 'shrink'], 'default': 'fit', 'enumDescriptions': [ - nls.localize('workbench.editor.tabSizing.fit', "Always keep tabs large enough to show the full editor label."), - nls.localize('workbench.editor.tabSizing.shrink', "Allow tabs to get smaller when the available space is not enough to show all tabs at once.") + localize('workbench.editor.tabSizing.fit', "Always keep tabs large enough to show the full editor label."), + localize('workbench.editor.tabSizing.shrink', "Allow tabs to get smaller when the available space is not enough to show all tabs at once.") ], - 'markdownDescription': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'tabSizing' }, "Controls the sizing of editor tabs. This value is ignored when `#workbench.editor.showTabs#` is disabled.") + 'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'tabSizing' }, "Controls the sizing of editor tabs. This value is ignored when `#workbench.editor.showTabs#` is disabled.") }, 'workbench.editor.pinnedTabSizing': { 'type': 'string', 'enum': ['normal', 'compact', 'shrink'], 'default': 'normal', 'enumDescriptions': [ - nls.localize('workbench.editor.pinnedTabSizing.normal', "A pinned tab inherits the look of non pinned tabs."), - nls.localize('workbench.editor.pinnedTabSizing.compact', "A pinned tab will show in a compact form with only icon or first letter of the editor name."), - nls.localize('workbench.editor.pinnedTabSizing.shrink', "A pinned tab shrinks to a compact fixed size showing parts of the editor name.") + localize('workbench.editor.pinnedTabSizing.normal', "A pinned tab inherits the look of non pinned tabs."), + localize('workbench.editor.pinnedTabSizing.compact', "A pinned tab will show in a compact form with only icon or first letter of the editor name."), + localize('workbench.editor.pinnedTabSizing.shrink', "A pinned tab shrinks to a compact fixed size showing parts of the editor name.") ], - 'markdownDescription': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'pinnedTabSizing' }, "Controls the sizing of pinned editor tabs. Pinned tabs are sorted to the beginning of all opened tabs and typically do not close until unpinned. This value is ignored when `#workbench.editor.showTabs#` is disabled.") + 'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'pinnedTabSizing' }, "Controls the sizing of pinned editor tabs. Pinned tabs are sorted to the beginning of all opened tabs and typically do not close until unpinned. This value is ignored when `#workbench.editor.showTabs#` is disabled.") }, 'workbench.editor.splitSizing': { 'type': 'string', 'enum': ['distribute', 'split'], 'default': 'distribute', 'enumDescriptions': [ - nls.localize('workbench.editor.splitSizingDistribute', "Splits all the editor groups to equal parts."), - nls.localize('workbench.editor.splitSizingSplit', "Splits the active editor group to equal parts.") + localize('workbench.editor.splitSizingDistribute', "Splits all the editor groups to equal parts."), + localize('workbench.editor.splitSizingSplit', "Splits the active editor group to equal parts.") ], - 'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'splitSizing' }, "Controls the sizing of editor groups when splitting them.") + 'description': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'splitSizing' }, "Controls the sizing of editor groups when splitting them.") }, 'workbench.editor.splitOnDragAndDrop': { 'type': 'boolean', 'default': true, - 'description': nls.localize('splitOnDragAndDrop', "Controls if editor groups can be split from drag and drop operations by dropping an editor or file on the edges of the editor area.") + 'description': localize('splitOnDragAndDrop', "Controls if editor groups can be split from drag and drop operations by dropping an editor or file on the edges of the editor area.") }, 'workbench.editor.focusRecentEditorAfterClose': { 'type': 'boolean', - 'description': nls.localize('focusRecentEditorAfterClose', "Controls whether tabs are closed in most recently used order or from left to right."), + 'description': localize('focusRecentEditorAfterClose', "Controls whether tabs are closed in most recently used order or from left to right."), 'default': true }, 'workbench.editor.showIcons': { 'type': 'boolean', - 'description': nls.localize('showIcons', "Controls whether opened editors should show with an icon or not. This requires a file icon theme to be enabled as well."), + 'description': localize('showIcons', "Controls whether opened editors should show with an icon or not. This requires a file icon theme to be enabled as well."), 'default': true }, 'workbench.editor.enablePreview': { 'type': 'boolean', - 'description': nls.localize('enablePreview', "Controls whether opened editors show as preview. Preview editors do not keep open and are reused until explicitly set to be kept open (e.g. via double click or editing) and show up with an italic font style."), + 'description': localize('enablePreview', "Controls whether opened editors show as preview. Preview editors do not keep open and are reused until explicitly set to be kept open (e.g. via double click or editing) and show up with an italic font style."), 'default': true }, 'workbench.editor.enablePreviewFromQuickOpen': { 'type': 'boolean', - 'markdownDescription': nls.localize('enablePreviewFromQuickOpen', "Controls whether editors opened from Quick Open show as preview. Preview editors do not keep open and are reused until explicitly set to be kept open (e.g. via double click or editing). This value is ignored when `#workbench.editor.enablePreview#` is disabled."), + 'markdownDescription': localize('enablePreviewFromQuickOpen', "Controls whether editors opened from Quick Open show as preview. Preview editors do not keep open and are reused until explicitly set to be kept open (e.g. via double click or editing). This value is ignored when `#workbench.editor.enablePreview#` is disabled."), 'default': false }, 'workbench.editor.enablePreviewFromCodeNavigation': { 'type': 'boolean', - 'markdownDescription': nls.localize('enablePreviewFromCodeNavigation', "Controls whether editors remain in preview when a code navigation is started from them. Preview editors do not keep open and are reused until explicitly set to be kept open (e.g. via double click or editing). This value is ignored when `#workbench.editor.enablePreview#` is disabled."), + 'markdownDescription': localize('enablePreviewFromCodeNavigation', "Controls whether editors remain in preview when a code navigation is started from them. Preview editors do not keep open and are reused until explicitly set to be kept open (e.g. via double click or editing). This value is ignored when `#workbench.editor.enablePreview#` is disabled."), 'default': false }, 'workbench.editor.closeOnFileDelete': { 'type': 'boolean', - 'description': nls.localize('closeOnFileDelete', "Controls whether editors showing a file that was opened during the session should close automatically when getting deleted or renamed by some other process. Disabling this will keep the editor open on such an event. Note that deleting from within the application will always close the editor and that dirty files will never close to preserve your data."), + 'description': localize('closeOnFileDelete', "Controls whether editors showing a file that was opened during the session should close automatically when getting deleted or renamed by some other process. Disabling this will keep the editor open on such an event. Note that deleting from within the application will always close the editor and that dirty files will never close to preserve your data."), 'default': false }, 'workbench.editor.openPositioning': { 'type': 'string', 'enum': ['left', 'right', 'first', 'last'], 'default': 'right', - 'markdownDescription': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'editorOpenPositioning' }, "Controls where editors open. Select `left` or `right` to open editors to the left or right of the currently active one. Select `first` or `last` to open editors independently from the currently active one.") + 'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'editorOpenPositioning' }, "Controls where editors open. Select `left` or `right` to open editors to the left or right of the currently active one. Select `first` or `last` to open editors independently from the currently active one.") }, 'workbench.editor.openSideBySideDirection': { 'type': 'string', 'enum': ['right', 'down'], 'default': 'right', - 'markdownDescription': nls.localize('sideBySideDirection', "Controls the default direction of editors that are opened side by side (e.g. from the explorer). By default, editors will open on the right hand side of the currently active one. If changed to `down`, the editors will open below the currently active one.") + 'markdownDescription': localize('sideBySideDirection', "Controls the default direction of editors that are opened side by side (e.g. from the explorer). By default, editors will open on the right hand side of the currently active one. If changed to `down`, the editors will open below the currently active one.") }, 'workbench.editor.closeEmptyGroups': { 'type': 'boolean', - 'description': nls.localize('closeEmptyGroups', "Controls the behavior of empty editor groups when the last tab in the group is closed. When enabled, empty groups will automatically close. When disabled, empty groups will remain part of the grid."), + 'description': localize('closeEmptyGroups', "Controls the behavior of empty editor groups when the last tab in the group is closed. When enabled, empty groups will automatically close. When disabled, empty groups will remain part of the grid."), 'default': true }, 'workbench.editor.revealIfOpen': { 'type': 'boolean', - 'description': nls.localize('revealIfOpen', "Controls whether an editor is revealed in any of the visible groups if opened. If disabled, an editor will prefer to open in the currently active editor group. If enabled, an already opened editor will be revealed instead of opened again in the currently active editor group. Note that there are some cases where this setting is ignored, e.g. when forcing an editor to open in a specific group or to the side of the currently active group."), + 'description': localize('revealIfOpen', "Controls whether an editor is revealed in any of the visible groups if opened. If disabled, an editor will prefer to open in the currently active editor group. If enabled, an already opened editor will be revealed instead of opened again in the currently active editor group. Note that there are some cases where this setting is ignored, e.g. when forcing an editor to open in a specific group or to the side of the currently active group."), 'default': false }, 'workbench.editor.mouseBackForwardToNavigate': { 'type': 'boolean', - 'description': nls.localize('mouseBackForwardToNavigate', "Navigate between open files using mouse buttons four and five if provided."), + 'description': localize('mouseBackForwardToNavigate', "Navigate between open files using mouse buttons four and five if provided."), 'default': true }, 'workbench.editor.restoreViewState': { 'type': 'boolean', - 'description': nls.localize('restoreViewState', "Restores the last view state (e.g. scroll position) when re-opening textual editors after they have been closed."), + 'description': localize('restoreViewState', "Restores the last view state (e.g. scroll position) when re-opening textual editors after they have been closed."), 'default': true, 'scope': ConfigurationScope.LANGUAGE_OVERRIDABLE }, 'workbench.editor.centeredLayoutAutoResize': { 'type': 'boolean', 'default': true, - 'description': nls.localize('centeredLayoutAutoResize', "Controls if the centered layout should automatically resize to maximum width when more than one group is open. Once only one group is open it will resize back to the original centered width.") + 'description': localize('centeredLayoutAutoResize', "Controls if the centered layout should automatically resize to maximum width when more than one group is open. Once only one group is open it will resize back to the original centered width.") }, 'workbench.editor.limit.enabled': { 'type': 'boolean', 'default': false, - 'description': nls.localize('limitEditorsEnablement', "Controls if the number of opened editors should be limited or not. When enabled, less recently used editors that are not dirty will close to make space for newly opening editors.") + 'description': localize('limitEditorsEnablement', "Controls if the number of opened editors should be limited or not. When enabled, less recently used editors that are not dirty will close to make space for newly opening editors.") }, 'workbench.editor.limit.value': { 'type': 'number', 'default': 10, 'exclusiveMinimum': 0, - 'markdownDescription': nls.localize('limitEditorsMaximum', "Controls the maximum number of opened editors. Use the `#workbench.editor.limit.perEditorGroup#` setting to control this limit per editor group or across all groups.") + 'markdownDescription': localize('limitEditorsMaximum', "Controls the maximum number of opened editors. Use the `#workbench.editor.limit.perEditorGroup#` setting to control this limit per editor group or across all groups.") }, 'workbench.editor.limit.perEditorGroup': { 'type': 'boolean', 'default': false, - 'description': nls.localize('perEditorGroup', "Controls if the limit of maximum opened editors should apply per editor group or across all editor groups.") + 'description': localize('perEditorGroup', "Controls if the limit of maximum opened editors should apply per editor group or across all editor groups.") }, 'workbench.commandPalette.history': { 'type': 'number', - 'description': nls.localize('commandHistory', "Controls the number of recently used commands to keep in history for the command palette. Set to 0 to disable command history."), + 'description': localize('commandHistory', "Controls the number of recently used commands to keep in history for the command palette. Set to 0 to disable command history."), 'default': 50 }, 'workbench.commandPalette.preserveInput': { 'type': 'boolean', - 'description': nls.localize('preserveInput', "Controls whether the last typed input to the command palette should be restored when opening it the next time."), + 'description': localize('preserveInput', "Controls whether the last typed input to the command palette should be restored when opening it the next time."), 'default': false }, 'workbench.quickOpen.closeOnFocusLost': { 'type': 'boolean', - 'description': nls.localize('closeOnFocusLost', "Controls whether Quick Open should close automatically once it loses focus."), + 'description': localize('closeOnFocusLost', "Controls whether Quick Open should close automatically once it loses focus."), 'default': true }, 'workbench.quickOpen.preserveInput': { 'type': 'boolean', - 'description': nls.localize('workbench.quickOpen.preserveInput', "Controls whether the last typed input to Quick Open should be restored when opening it the next time."), + 'description': localize('workbench.quickOpen.preserveInput', "Controls whether the last typed input to Quick Open should be restored when opening it the next time."), 'default': false }, 'workbench.settings.openDefaultSettings': { 'type': 'boolean', - 'description': nls.localize('openDefaultSettings', "Controls whether opening settings also opens an editor showing all default settings."), + 'description': localize('openDefaultSettings', "Controls whether opening settings also opens an editor showing all default settings."), 'default': false }, 'workbench.settings.useSplitJSON': { 'type': 'boolean', - 'markdownDescription': nls.localize('useSplitJSON', "Controls whether to use the split JSON editor when editing settings as JSON."), + 'markdownDescription': localize('useSplitJSON', "Controls whether to use the split JSON editor when editing settings as JSON."), 'default': false }, 'workbench.settings.openDefaultKeybindings': { 'type': 'boolean', - 'description': nls.localize('openDefaultKeybindings', "Controls whether opening keybinding settings also opens an editor showing all default keybindings."), + 'description': localize('openDefaultKeybindings', "Controls whether opening keybinding settings also opens an editor showing all default keybindings."), 'default': false }, 'workbench.sideBar.location': { 'type': 'string', 'enum': ['left', 'right'], 'default': 'left', - 'description': nls.localize('sideBarLocation', "Controls the location of the sidebar and activity bar. They can either show on the left or right of the workbench.") + 'description': localize('sideBarLocation', "Controls the location of the sidebar and activity bar. They can either show on the left or right of the workbench.") }, 'workbench.panel.defaultLocation': { '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, right, or left of the workbench.") + 'description': 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.panel.opensMaximized': { 'type': 'string', 'enum': ['always', 'never', 'preserve'], 'default': 'preserve', - 'description': nls.localize('panelOpensMaximized', "Controls whether the panel opens maximized. It can either always open maximized, never open maximized, or open to the last state it was in before being closed."), + 'description': localize('panelOpensMaximized', "Controls whether the panel opens maximized. It can either always open maximized, never open maximized, or open to the last state it was in before being closed."), 'enumDescriptions': [ - nls.localize('workbench.panel.opensMaximized.always', "Always maximize the panel when opening it."), - nls.localize('workbench.panel.opensMaximized.never', "Never maximize the panel when opening it. The panel will open un-maximized."), - nls.localize('workbench.panel.opensMaximized.preserve', "Open the panel to the state that it was in, before it was closed.") + localize('workbench.panel.opensMaximized.always', "Always maximize the panel when opening it."), + localize('workbench.panel.opensMaximized.never', "Never maximize the panel when opening it. The panel will open un-maximized."), + localize('workbench.panel.opensMaximized.preserve', "Open the panel to the state that it was in, before it was closed.") ] }, 'workbench.statusBar.visible': { 'type': 'boolean', 'default': true, - 'description': nls.localize('statusBarVisibility', "Controls the visibility of the status bar at the bottom of the workbench.") + 'description': localize('statusBarVisibility', "Controls the visibility of the status bar at the bottom of the workbench.") }, 'workbench.activityBar.visible': { 'type': 'boolean', 'default': true, - 'description': nls.localize('activityBarVisibility', "Controls the visibility of the activity bar in the workbench.") + 'description': localize('activityBarVisibility', "Controls the visibility of the activity bar in the workbench.") }, 'workbench.activityBar.iconClickBehavior': { 'type': 'string', 'enum': ['toggle', 'focus'], 'default': 'toggle', - 'description': nls.localize('activityBarIconClickBehavior', "Controls the behavior of clicking an activity bar icon in the workbench."), + 'description': localize('activityBarIconClickBehavior', "Controls the behavior of clicking an activity bar icon in the workbench."), 'enumDescriptions': [ - nls.localize('workbench.activityBar.iconClickBehavior.toggle', "Hide the side bar if the clicked item is already visible."), - nls.localize('workbench.activityBar.iconClickBehavior.focus', "Focus side bar if the clicked item is already visible.") + localize('workbench.activityBar.iconClickBehavior.toggle', "Hide the side bar if the clicked item is already visible."), + localize('workbench.activityBar.iconClickBehavior.focus', "Focus side bar if the clicked item is already visible.") ] }, 'workbench.view.alwaysShowHeaderActions': { 'type': 'boolean', 'default': false, - 'description': nls.localize('viewVisibility', "Controls the visibility of view header actions. View header actions may either be always visible, or only visible when that view is focused or hovered over.") + 'description': localize('viewVisibility', "Controls the visibility of view header actions. View header actions may either be always visible, or only visible when that view is focused or hovered over.") }, 'workbench.fontAliasing': { 'type': 'string', 'enum': ['default', 'antialiased', 'none', 'auto'], 'default': 'default', 'description': - nls.localize('fontAliasing', "Controls font aliasing method in the workbench."), + localize('fontAliasing', "Controls font aliasing method in the workbench."), 'enumDescriptions': [ - nls.localize('workbench.fontAliasing.default', "Sub-pixel font smoothing. On most non-retina displays this will give the sharpest text."), - nls.localize('workbench.fontAliasing.antialiased', "Smooth the font on the level of the pixel, as opposed to the subpixel. Can make the font appear lighter overall."), - nls.localize('workbench.fontAliasing.none', "Disables font smoothing. Text will show with jagged sharp edges."), - nls.localize('workbench.fontAliasing.auto', "Applies `default` or `antialiased` automatically based on the DPI of displays.") + localize('workbench.fontAliasing.default', "Sub-pixel font smoothing. On most non-retina displays this will give the sharpest text."), + localize('workbench.fontAliasing.antialiased', "Smooth the font on the level of the pixel, as opposed to the subpixel. Can make the font appear lighter overall."), + localize('workbench.fontAliasing.none', "Disables font smoothing. Text will show with jagged sharp edges."), + localize('workbench.fontAliasing.auto', "Applies `default` or `antialiased` automatically based on the DPI of displays.") ], 'included': isMacintosh }, @@ -313,10 +313,10 @@ import { isStandalone } from 'vs/base/browser/browser'; 'type': 'string', 'enum': ['ui', 'json'], 'enumDescriptions': [ - nls.localize('settings.editor.ui', "Use the settings UI editor."), - nls.localize('settings.editor.json', "Use the JSON file editor."), + localize('settings.editor.ui', "Use the settings UI editor."), + localize('settings.editor.json', "Use the JSON file editor."), ], - 'description': nls.localize('settings.editor.desc', "Determines which settings editor to use by default."), + 'description': localize('settings.editor.desc', "Determines which settings editor to use by default."), 'default': 'ui', 'scope': ConfigurationScope.WINDOW } @@ -325,28 +325,28 @@ import { isStandalone } from 'vs/base/browser/browser'; // Window - let windowTitleDescription = nls.localize('windowTitle', "Controls the window title based on the active editor. Variables are substituted based on the context:"); + let windowTitleDescription = localize('windowTitle', "Controls the window title based on the active editor. Variables are substituted based on the context:"); windowTitleDescription += '\n- ' + [ - nls.localize('activeEditorShort', "`\${activeEditorShort}`: the file name (e.g. myFile.txt)."), - nls.localize('activeEditorMedium', "`\${activeEditorMedium}`: the path of the file relative to the workspace folder (e.g. myFolder/myFileFolder/myFile.txt)."), - nls.localize('activeEditorLong', "`\${activeEditorLong}`: the full path of the file (e.g. /Users/Development/myFolder/myFileFolder/myFile.txt)."), - nls.localize('activeFolderShort', "`\${activeFolderShort}`: the name of the folder the file is contained in (e.g. myFileFolder)."), - nls.localize('activeFolderMedium', "`\${activeFolderMedium}`: the path of the folder the file is contained in, relative to the workspace folder (e.g. myFolder/myFileFolder)."), - nls.localize('activeFolderLong', "`\${activeFolderLong}`: the full path of the folder the file is contained in (e.g. /Users/Development/myFolder/myFileFolder)."), - nls.localize('folderName', "`\${folderName}`: name of the workspace folder the file is contained in (e.g. myFolder)."), - nls.localize('folderPath', "`\${folderPath}`: file path of the workspace folder the file is contained in (e.g. /Users/Development/myFolder)."), - nls.localize('rootName', "`\${rootName}`: name of the opened workspace or folder (e.g. myFolder or myWorkspace)."), - nls.localize('rootPath', "`\${rootPath}`: file path of the opened workspace or folder (e.g. /Users/Development/myWorkspace)."), - nls.localize('appName', "`\${appName}`: e.g. VS Code."), - nls.localize('remoteName', "`\${remoteName}`: e.g. SSH"), - nls.localize('dirty', "`\${dirty}`: a dirty indicator if the active editor is dirty."), - nls.localize('separator', "`\${separator}`: a conditional separator (\" - \") that only shows when surrounded by variables with values or static text.") + localize('activeEditorShort', "`\${activeEditorShort}`: the file name (e.g. myFile.txt)."), + localize('activeEditorMedium', "`\${activeEditorMedium}`: the path of the file relative to the workspace folder (e.g. myFolder/myFileFolder/myFile.txt)."), + localize('activeEditorLong', "`\${activeEditorLong}`: the full path of the file (e.g. /Users/Development/myFolder/myFileFolder/myFile.txt)."), + localize('activeFolderShort', "`\${activeFolderShort}`: the name of the folder the file is contained in (e.g. myFileFolder)."), + localize('activeFolderMedium', "`\${activeFolderMedium}`: the path of the folder the file is contained in, relative to the workspace folder (e.g. myFolder/myFileFolder)."), + localize('activeFolderLong', "`\${activeFolderLong}`: the full path of the folder the file is contained in (e.g. /Users/Development/myFolder/myFileFolder)."), + localize('folderName', "`\${folderName}`: name of the workspace folder the file is contained in (e.g. myFolder)."), + localize('folderPath', "`\${folderPath}`: file path of the workspace folder the file is contained in (e.g. /Users/Development/myFolder)."), + localize('rootName', "`\${rootName}`: name of the opened workspace or folder (e.g. myFolder or myWorkspace)."), + localize('rootPath', "`\${rootPath}`: file path of the opened workspace or folder (e.g. /Users/Development/myWorkspace)."), + localize('appName', "`\${appName}`: e.g. VS Code."), + localize('remoteName', "`\${remoteName}`: e.g. SSH"), + localize('dirty', "`\${dirty}`: a dirty indicator if the active editor is dirty."), + localize('separator', "`\${separator}`: a conditional separator (\" - \") that only shows when surrounded by variables with values or static text.") ].join('\n- '); // intentionally concatenated to not produce a string that is too long for translations registry.registerConfiguration({ 'id': 'window', 'order': 8, - 'title': nls.localize('windowConfigurationTitle', "Window"), + 'title': localize('windowConfigurationTitle', "Window"), 'type': 'object', 'properties': { 'window.title': { @@ -368,80 +368,80 @@ import { isStandalone } from 'vs/base/browser/browser'; 'window.titleSeparator': { 'type': 'string', 'default': isMacintosh ? ' — ' : ' - ', - 'markdownDescription': nls.localize("window.titleSeparator", "Separator used by `window.title`.") + 'markdownDescription': localize("window.titleSeparator", "Separator used by `window.title`.") }, 'window.menuBarVisibility': { 'type': 'string', 'enum': ['classic', 'visible', 'toggle', 'hidden', 'compact'], 'markdownEnumDescriptions': [ - nls.localize('window.menuBarVisibility.classic', "Menu is displayed at the top of the window and only hidden in full screen mode."), - nls.localize('window.menuBarVisibility.visible', "Menu is always visible at the top of the window even in full screen mode."), + localize('window.menuBarVisibility.classic', "Menu is displayed at the top of the window and only hidden in full screen mode."), + localize('window.menuBarVisibility.visible', "Menu is always visible at the top of the window even in full screen mode."), isMacintosh ? - nls.localize('window.menuBarVisibility.toggle.mac', "Menu is hidden but can be displayed at the top of the window by executing the `Focus Application Menu` command.") : - nls.localize('window.menuBarVisibility.toggle', "Menu is hidden but can be displayed at the top of the window via the Alt key."), - nls.localize('window.menuBarVisibility.hidden', "Menu is always hidden."), - nls.localize('window.menuBarVisibility.compact', "Menu is displayed as a compact button in the sidebar. This value is ignored when `#window.titleBarStyle#` is `native`.") + localize('window.menuBarVisibility.toggle.mac', "Menu is hidden but can be displayed at the top of the window by executing the `Focus Application Menu` command.") : + localize('window.menuBarVisibility.toggle', "Menu is hidden but can be displayed at the top of the window via the Alt key."), + localize('window.menuBarVisibility.hidden', "Menu is always hidden."), + localize('window.menuBarVisibility.compact', "Menu is displayed as a compact button in the sidebar. This value is ignored when `#window.titleBarStyle#` is `native`.") ], 'default': isWeb ? 'compact' : 'classic', 'scope': ConfigurationScope.APPLICATION, 'markdownDescription': isMacintosh ? - nls.localize('menuBarVisibility.mac', "Control the visibility of the menu bar. A setting of 'toggle' means that the menu bar is hidden and executing `Focus Application Menu` will show it. A setting of 'compact' will move the menu into the sidebar.") : - nls.localize('menuBarVisibility', "Control the visibility of the menu bar. A setting of 'toggle' means that the menu bar is hidden and a single press of the Alt key will show it. A setting of 'compact' will move the menu into the sidebar."), + localize('menuBarVisibility.mac', "Control the visibility of the menu bar. A setting of 'toggle' means that the menu bar is hidden and executing `Focus Application Menu` will show it. A setting of 'compact' will move the menu into the sidebar.") : + localize('menuBarVisibility', "Control the visibility of the menu bar. A setting of 'toggle' means that the menu bar is hidden and a single press of the Alt key will show it. A setting of 'compact' will move the menu into the sidebar."), 'included': isWindows || isLinux || isWeb }, 'window.enableMenuBarMnemonics': { 'type': 'boolean', 'default': true, 'scope': ConfigurationScope.APPLICATION, - 'description': nls.localize('enableMenuBarMnemonics', "Controls whether the main menus can be opened via Alt-key shortcuts. Disabling mnemonics allows to bind these Alt-key shortcuts to editor commands instead."), + 'description': localize('enableMenuBarMnemonics', "Controls whether the main menus can be opened via Alt-key shortcuts. Disabling mnemonics allows to bind these Alt-key shortcuts to editor commands instead."), 'included': isWindows || isLinux }, 'window.customMenuBarAltFocus': { 'type': 'boolean', 'default': true, 'scope': ConfigurationScope.APPLICATION, - 'markdownDescription': nls.localize('customMenuBarAltFocus', "Controls whether the menu bar will be focused by pressing the Alt-key. This setting has no effect on toggling the menu bar with the Alt-key."), + 'markdownDescription': localize('customMenuBarAltFocus', "Controls whether the menu bar will be focused by pressing the Alt-key. This setting has no effect on toggling the menu bar with the Alt-key."), 'included': isWindows || isLinux }, 'window.openFilesInNewWindow': { 'type': 'string', 'enum': ['on', 'off', 'default'], 'enumDescriptions': [ - nls.localize('window.openFilesInNewWindow.on', "Files will open in a new window."), - nls.localize('window.openFilesInNewWindow.off', "Files will open in the window with the files' folder open or the last active window."), + localize('window.openFilesInNewWindow.on', "Files will open in a new window."), + localize('window.openFilesInNewWindow.off', "Files will open in the window with the files' folder open or the last active window."), isMacintosh ? - nls.localize('window.openFilesInNewWindow.defaultMac', "Files will open in the window with the files' folder open or the last active window unless opened via the Dock or from Finder.") : - nls.localize('window.openFilesInNewWindow.default', "Files will open in a new window unless picked from within the application (e.g. via the File menu).") + localize('window.openFilesInNewWindow.defaultMac', "Files will open in the window with the files' folder open or the last active window unless opened via the Dock or from Finder.") : + localize('window.openFilesInNewWindow.default', "Files will open in a new window unless picked from within the application (e.g. via the File menu).") ], 'default': 'off', 'scope': ConfigurationScope.APPLICATION, 'markdownDescription': isMacintosh ? - nls.localize('openFilesInNewWindowMac', "Controls whether files should open in a new window. \nNote that there can still be cases where this setting is ignored (e.g. when using the `--new-window` or `--reuse-window` command line option).") : - nls.localize('openFilesInNewWindow', "Controls whether files should open in a new window.\nNote that there can still be cases where this setting is ignored (e.g. when using the `--new-window` or `--reuse-window` command line option).") + localize('openFilesInNewWindowMac', "Controls whether files should open in a new window. \nNote that there can still be cases where this setting is ignored (e.g. when using the `--new-window` or `--reuse-window` command line option).") : + localize('openFilesInNewWindow', "Controls whether files should open in a new window.\nNote that there can still be cases where this setting is ignored (e.g. when using the `--new-window` or `--reuse-window` command line option).") }, 'window.openFoldersInNewWindow': { 'type': 'string', 'enum': ['on', 'off', 'default'], 'enumDescriptions': [ - nls.localize('window.openFoldersInNewWindow.on', "Folders will open in a new window."), - nls.localize('window.openFoldersInNewWindow.off', "Folders will replace the last active window."), - nls.localize('window.openFoldersInNewWindow.default', "Folders will open in a new window unless a folder is picked from within the application (e.g. via the File menu).") + localize('window.openFoldersInNewWindow.on', "Folders will open in a new window."), + localize('window.openFoldersInNewWindow.off', "Folders will replace the last active window."), + localize('window.openFoldersInNewWindow.default', "Folders will open in a new window unless a folder is picked from within the application (e.g. via the File menu).") ], 'default': 'default', 'scope': ConfigurationScope.APPLICATION, - 'markdownDescription': nls.localize('openFoldersInNewWindow', "Controls whether folders should open in a new window or replace the last active window.\nNote that there can still be cases where this setting is ignored (e.g. when using the `--new-window` or `--reuse-window` command line option).") + 'markdownDescription': localize('openFoldersInNewWindow', "Controls whether folders should open in a new window or replace the last active window.\nNote that there can still be cases where this setting is ignored (e.g. when using the `--new-window` or `--reuse-window` command line option).") }, 'window.confirmBeforeClose': { 'type': 'string', 'enum': ['always', 'keyboardOnly', 'never'], 'enumDescriptions': [ - nls.localize('window.confirmBeforeClose.always', "Always try to ask for confirmation. Note that browsers may still decide to close a tab or window without confirmation."), - nls.localize('window.confirmBeforeClose.keyboardOnly', "Only ask for confirmation if a keybinding was detected. Note that detection may not be possible in some cases."), - nls.localize('window.confirmBeforeClose.never', "Never explicitly ask for confirmation unless data loss is imminent.") + localize('window.confirmBeforeClose.always', "Always try to ask for confirmation. Note that browsers may still decide to close a tab or window without confirmation."), + localize('window.confirmBeforeClose.keyboardOnly', "Only ask for confirmation if a keybinding was detected. Note that detection may not be possible in some cases."), + localize('window.confirmBeforeClose.never', "Never explicitly ask for confirmation unless data loss is imminent.") ], 'default': isWeb && !isStandalone ? 'keyboardOnly' : 'never', // on by default in web, unless PWA - 'description': nls.localize('confirmBeforeCloseWeb', "Controls whether to show a confirmation dialog before closing the browser tab or window. Note that even if enabled, browsers may still decide to close a tab or window without confirmation and that this setting is only a hint that may not work in all cases."), + 'description': localize('confirmBeforeCloseWeb', "Controls whether to show a confirmation dialog before closing the browser tab or window. Note that even if enabled, browsers may still decide to close a tab or window without confirmation and that this setting is only a hint that may not work in all cases."), 'scope': ConfigurationScope.APPLICATION, 'included': isWeb } @@ -452,48 +452,48 @@ import { isStandalone } from 'vs/base/browser/browser'; registry.registerConfiguration({ 'id': 'zenMode', 'order': 9, - 'title': nls.localize('zenModeConfigurationTitle', "Zen Mode"), + 'title': localize('zenModeConfigurationTitle', "Zen Mode"), 'type': 'object', 'properties': { 'zenMode.fullScreen': { 'type': 'boolean', 'default': true, - 'description': nls.localize('zenMode.fullScreen', "Controls whether turning on Zen Mode also puts the workbench into full screen mode.") + 'description': localize('zenMode.fullScreen', "Controls whether turning on Zen Mode also puts the workbench into full screen mode.") }, 'zenMode.centerLayout': { 'type': 'boolean', 'default': true, - 'description': nls.localize('zenMode.centerLayout', "Controls whether turning on Zen Mode also centers the layout.") + 'description': localize('zenMode.centerLayout', "Controls whether turning on Zen Mode also centers the layout.") }, 'zenMode.hideTabs': { 'type': 'boolean', 'default': true, - 'description': nls.localize('zenMode.hideTabs', "Controls whether turning on Zen Mode also hides workbench tabs.") + 'description': localize('zenMode.hideTabs', "Controls whether turning on Zen Mode also hides workbench tabs.") }, 'zenMode.hideStatusBar': { 'type': 'boolean', 'default': true, - 'description': nls.localize('zenMode.hideStatusBar', "Controls whether turning on Zen Mode also hides the status bar at the bottom of the workbench.") + 'description': localize('zenMode.hideStatusBar', "Controls whether turning on Zen Mode also hides the status bar at the bottom of the workbench.") }, 'zenMode.hideActivityBar': { 'type': 'boolean', 'default': true, - 'description': nls.localize('zenMode.hideActivityBar', "Controls whether turning on Zen Mode also hides the activity bar either at the left or right of the workbench.") + 'description': localize('zenMode.hideActivityBar', "Controls whether turning on Zen Mode also hides the activity bar either at the left or right of the workbench.") }, 'zenMode.hideLineNumbers': { 'type': 'boolean', 'default': true, - 'description': nls.localize('zenMode.hideLineNumbers', "Controls whether turning on Zen Mode also hides the editor line numbers.") + 'description': localize('zenMode.hideLineNumbers', "Controls whether turning on Zen Mode also hides the editor line numbers.") }, 'zenMode.restore': { 'type': 'boolean', 'default': true, - 'description': nls.localize('zenMode.restore', "Controls whether a window should restore to zen mode if it was exited in zen mode.") + 'description': localize('zenMode.restore', "Controls whether a window should restore to zen mode if it was exited in zen mode.") }, 'zenMode.silentNotifications': { 'type': 'boolean', 'default': true, - 'description': nls.localize('zenMode.silentNotifications', "Controls whether notifications are shown while in zen mode. If true, only error notifications will pop out.") + 'description': localize('zenMode.silentNotifications', "Controls whether notifications are shown while in zen mode. If true, only error notifications will pop out.") } } }); diff --git a/src/vs/workbench/browser/workbench.ts b/src/vs/workbench/browser/workbench.ts index 29c56c5202c..43d66630da8 100644 --- a/src/vs/workbench/browser/workbench.ts +++ b/src/vs/workbench/browser/workbench.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/workbench/browser/style'; - import { localize } from 'vs/nls'; import { Emitter, setGlobalLeakWarningThreshold } from 'vs/base/common/event'; import { runWhenIdle } from 'vs/base/common/async'; diff --git a/src/vs/workbench/common/resources.ts b/src/vs/workbench/common/resources.ts index 94e7e7a4bac..27e05b1d228 100644 --- a/src/vs/workbench/common/resources.ts +++ b/src/vs/workbench/common/resources.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import * as objects from 'vs/base/common/objects'; +import { deepClone, equals } from 'vs/base/common/objects'; import { Emitter } from 'vs/base/common/event'; import { basename, dirname, extname, relativePath } from 'vs/base/common/resources'; import { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; @@ -159,11 +159,11 @@ export class ResourceGlobMatcher extends Disposable { // Add excludes per workspaces that got added this.contextService.getWorkspace().folders.forEach(folder => { const rootExcludes = this.globFn(folder.uri); - if (!this.mapRootToExpressionConfig.has(folder.uri.toString()) || !objects.equals(this.mapRootToExpressionConfig.get(folder.uri.toString()), rootExcludes)) { + if (!this.mapRootToExpressionConfig.has(folder.uri.toString()) || !equals(this.mapRootToExpressionConfig.get(folder.uri.toString()), rootExcludes)) { changed = true; this.mapRootToParsedExpression.set(folder.uri.toString(), parse(rootExcludes)); - this.mapRootToExpressionConfig.set(folder.uri.toString(), objects.deepClone(rootExcludes)); + this.mapRootToExpressionConfig.set(folder.uri.toString(), deepClone(rootExcludes)); } }); @@ -183,11 +183,11 @@ export class ResourceGlobMatcher extends Disposable { // Always set for resources outside root as well const globalExcludes = this.globFn(); - if (!this.mapRootToExpressionConfig.has(ResourceGlobMatcher.NO_ROOT) || !objects.equals(this.mapRootToExpressionConfig.get(ResourceGlobMatcher.NO_ROOT), globalExcludes)) { + if (!this.mapRootToExpressionConfig.has(ResourceGlobMatcher.NO_ROOT) || !equals(this.mapRootToExpressionConfig.get(ResourceGlobMatcher.NO_ROOT), globalExcludes)) { changed = true; this.mapRootToParsedExpression.set(ResourceGlobMatcher.NO_ROOT, parse(globalExcludes)); - this.mapRootToExpressionConfig.set(ResourceGlobMatcher.NO_ROOT, objects.deepClone(globalExcludes)); + this.mapRootToExpressionConfig.set(ResourceGlobMatcher.NO_ROOT, deepClone(globalExcludes)); } if (fromEvent && changed) { diff --git a/src/vs/workbench/common/theme.ts b/src/vs/workbench/common/theme.ts index 317cfd2fcd9..272f767d2e8 100644 --- a/src/vs/workbench/common/theme.ts +++ b/src/vs/workbench/common/theme.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { registerColor, editorBackground, contrastBorder, transparent, editorWidgetBackground, textLinkForeground, lighten, darken, focusBorder, activeContrastBorder, editorWidgetForeground, editorErrorForeground, editorWarningForeground, editorInfoForeground, treeIndentGuidesStroke, errorForeground } from 'vs/platform/theme/common/colorRegistry'; import { IColorTheme } from 'vs/platform/theme/common/themeService'; import { Color } from 'vs/base/common/color'; @@ -29,25 +29,25 @@ export const TAB_ACTIVE_BACKGROUND = registerColor('tab.activeBackground', { dark: editorBackground, light: editorBackground, hc: editorBackground -}, nls.localize('tabActiveBackground', "Active tab background color in an active group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('tabActiveBackground', "Active tab background color in an active group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); export const TAB_UNFOCUSED_ACTIVE_BACKGROUND = registerColor('tab.unfocusedActiveBackground', { dark: TAB_ACTIVE_BACKGROUND, light: TAB_ACTIVE_BACKGROUND, hc: TAB_ACTIVE_BACKGROUND -}, nls.localize('tabUnfocusedActiveBackground', "Active tab background color in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('tabUnfocusedActiveBackground', "Active tab background color in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); export const TAB_INACTIVE_BACKGROUND = registerColor('tab.inactiveBackground', { dark: '#2D2D2D', light: '#ECECEC', hc: null -}, nls.localize('tabInactiveBackground', "Inactive tab background color in an active group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('tabInactiveBackground', "Inactive tab background color in an active group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); export const TAB_UNFOCUSED_INACTIVE_BACKGROUND = registerColor('tab.unfocusedInactiveBackground', { dark: TAB_INACTIVE_BACKGROUND, light: TAB_INACTIVE_BACKGROUND, hc: TAB_INACTIVE_BACKGROUND -}, nls.localize('tabUnfocusedInactiveBackground', "Inactive tab background color in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('tabUnfocusedInactiveBackground', "Inactive tab background color in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); //#endregion @@ -57,25 +57,25 @@ export const TAB_ACTIVE_FOREGROUND = registerColor('tab.activeForeground', { dark: Color.white, light: '#333333', hc: Color.white -}, nls.localize('tabActiveForeground', "Active tab foreground color in an active group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('tabActiveForeground', "Active tab foreground color in an active group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); export const TAB_INACTIVE_FOREGROUND = registerColor('tab.inactiveForeground', { dark: transparent(TAB_ACTIVE_FOREGROUND, 0.5), light: transparent(TAB_ACTIVE_FOREGROUND, 0.7), hc: Color.white -}, nls.localize('tabInactiveForeground', "Inactive tab foreground color in an active group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('tabInactiveForeground', "Inactive tab foreground color in an active group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); export const TAB_UNFOCUSED_ACTIVE_FOREGROUND = registerColor('tab.unfocusedActiveForeground', { dark: transparent(TAB_ACTIVE_FOREGROUND, 0.5), light: transparent(TAB_ACTIVE_FOREGROUND, 0.7), hc: Color.white -}, nls.localize('tabUnfocusedActiveForeground', "Active tab foreground color in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('tabUnfocusedActiveForeground', "Active tab foreground color in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); export const TAB_UNFOCUSED_INACTIVE_FOREGROUND = registerColor('tab.unfocusedInactiveForeground', { dark: transparent(TAB_INACTIVE_FOREGROUND, 0.5), light: transparent(TAB_INACTIVE_FOREGROUND, 0.5), hc: Color.white -}, nls.localize('tabUnfocusedInactiveForeground', "Inactive tab foreground color in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('tabUnfocusedInactiveForeground', "Inactive tab foreground color in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); //#endregion @@ -85,25 +85,25 @@ export const TAB_HOVER_BACKGROUND = registerColor('tab.hoverBackground', { dark: null, light: null, hc: null -}, nls.localize('tabHoverBackground', "Tab background color when hovering. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('tabHoverBackground', "Tab background color when hovering. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); export const TAB_UNFOCUSED_HOVER_BACKGROUND = registerColor('tab.unfocusedHoverBackground', { dark: transparent(TAB_HOVER_BACKGROUND, 0.5), light: transparent(TAB_HOVER_BACKGROUND, 0.7), hc: null -}, nls.localize('tabUnfocusedHoverBackground', "Tab background color in an unfocused group when hovering. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('tabUnfocusedHoverBackground', "Tab background color in an unfocused group when hovering. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); export const TAB_HOVER_FOREGROUND = registerColor('tab.hoverForeground', { dark: null, light: null, hc: null -}, nls.localize('tabHoverForeground', "Tab foreground color when hovering. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('tabHoverForeground', "Tab foreground color when hovering. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); export const TAB_UNFOCUSED_HOVER_FOREGROUND = registerColor('tab.unfocusedHoverForeground', { dark: transparent(TAB_HOVER_FOREGROUND, 0.5), light: transparent(TAB_HOVER_FOREGROUND, 0.5), hc: null -}, nls.localize('tabUnfocusedHoverForeground', "Tab foreground color in an unfocused group when hovering. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('tabUnfocusedHoverForeground', "Tab foreground color in an unfocused group when hovering. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); //#endregion @@ -113,49 +113,49 @@ export const TAB_BORDER = registerColor('tab.border', { dark: '#252526', light: '#F3F3F3', hc: contrastBorder -}, nls.localize('tabBorder', "Border to separate tabs from each other. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('tabBorder', "Border to separate tabs from each other. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); export const TAB_LAST_PINNED_BORDER = registerColor('tab.lastPinnedBorder', { dark: treeIndentGuidesStroke, light: treeIndentGuidesStroke, hc: contrastBorder -}, nls.localize('lastPinnedTabBorder', "Border to separate pinned tabs from other tabs. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('lastPinnedTabBorder', "Border to separate pinned tabs from other tabs. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); export const TAB_ACTIVE_BORDER = registerColor('tab.activeBorder', { dark: null, light: null, hc: null -}, nls.localize('tabActiveBorder', "Border on the bottom of an active tab. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('tabActiveBorder', "Border on the bottom of an active tab. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); export const TAB_UNFOCUSED_ACTIVE_BORDER = registerColor('tab.unfocusedActiveBorder', { dark: transparent(TAB_ACTIVE_BORDER, 0.5), light: transparent(TAB_ACTIVE_BORDER, 0.7), hc: null -}, nls.localize('tabActiveUnfocusedBorder', "Border on the bottom of an active tab in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('tabActiveUnfocusedBorder', "Border on the bottom of an active tab in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); export const TAB_ACTIVE_BORDER_TOP = registerColor('tab.activeBorderTop', { dark: null, light: null, hc: null -}, nls.localize('tabActiveBorderTop', "Border to the top of an active tab. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('tabActiveBorderTop', "Border to the top of an active tab. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); export const TAB_UNFOCUSED_ACTIVE_BORDER_TOP = registerColor('tab.unfocusedActiveBorderTop', { dark: transparent(TAB_ACTIVE_BORDER_TOP, 0.5), light: transparent(TAB_ACTIVE_BORDER_TOP, 0.7), hc: null -}, nls.localize('tabActiveUnfocusedBorderTop', "Border to the top of an active tab in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('tabActiveUnfocusedBorderTop', "Border to the top of an active tab in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); export const TAB_HOVER_BORDER = registerColor('tab.hoverBorder', { dark: null, light: null, hc: null -}, nls.localize('tabHoverBorder', "Border to highlight tabs when hovering. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('tabHoverBorder', "Border to highlight tabs when hovering. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); export const TAB_UNFOCUSED_HOVER_BORDER = registerColor('tab.unfocusedHoverBorder', { dark: transparent(TAB_HOVER_BORDER, 0.5), light: transparent(TAB_HOVER_BORDER, 0.7), hc: null -}, nls.localize('tabUnfocusedHoverBorder', "Border to highlight tabs in an unfocused group when hovering. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('tabUnfocusedHoverBorder', "Border to highlight tabs in an unfocused group when hovering. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); //#endregion @@ -165,25 +165,25 @@ export const TAB_ACTIVE_MODIFIED_BORDER = registerColor('tab.activeModifiedBorde dark: '#3399CC', light: '#33AAEE', hc: null -}, nls.localize('tabActiveModifiedBorder', "Border on the top of modified (dirty) active tabs in an active group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('tabActiveModifiedBorder', "Border on the top of modified (dirty) active tabs in an active group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); export const TAB_INACTIVE_MODIFIED_BORDER = registerColor('tab.inactiveModifiedBorder', { dark: transparent(TAB_ACTIVE_MODIFIED_BORDER, 0.5), light: transparent(TAB_ACTIVE_MODIFIED_BORDER, 0.5), hc: Color.white -}, nls.localize('tabInactiveModifiedBorder', "Border on the top of modified (dirty) inactive tabs in an active group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('tabInactiveModifiedBorder', "Border on the top of modified (dirty) inactive tabs in an active group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); export const TAB_UNFOCUSED_ACTIVE_MODIFIED_BORDER = registerColor('tab.unfocusedActiveModifiedBorder', { dark: transparent(TAB_ACTIVE_MODIFIED_BORDER, 0.5), light: transparent(TAB_ACTIVE_MODIFIED_BORDER, 0.7), hc: Color.white -}, nls.localize('unfocusedActiveModifiedBorder', "Border on the top of modified (dirty) active tabs in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('unfocusedActiveModifiedBorder', "Border on the top of modified (dirty) active tabs in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); export const TAB_UNFOCUSED_INACTIVE_MODIFIED_BORDER = registerColor('tab.unfocusedInactiveModifiedBorder', { dark: transparent(TAB_INACTIVE_MODIFIED_BORDER, 0.5), light: transparent(TAB_INACTIVE_MODIFIED_BORDER, 0.5), hc: Color.white -}, nls.localize('unfocusedINactiveModifiedBorder', "Border on the top of modified (dirty) inactive tabs in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); +}, localize('unfocusedINactiveModifiedBorder', "Border on the top of modified (dirty) inactive tabs in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); //#endregion @@ -193,61 +193,61 @@ export const EDITOR_PANE_BACKGROUND = registerColor('editorPane.background', { dark: editorBackground, light: editorBackground, hc: editorBackground -}, nls.localize('editorPaneBackground', "Background color of the editor pane visible on the left and right side of the centered editor layout.")); +}, localize('editorPaneBackground', "Background color of the editor pane visible on the left and right side of the centered editor layout.")); registerColor('editorGroup.background', { dark: null, light: null, hc: null -}, nls.localize('editorGroupBackground', "Deprecated background color of an editor group."), false, nls.localize('deprecatedEditorGroupBackground', "Deprecated: Background color of an editor group is no longer being supported with the introduction of the grid editor layout. You can use editorGroup.emptyBackground to set the background color of empty editor groups.")); +}, localize('editorGroupBackground', "Deprecated background color of an editor group."), false, localize('deprecatedEditorGroupBackground', "Deprecated: Background color of an editor group is no longer being supported with the introduction of the grid editor layout. You can use editorGroup.emptyBackground to set the background color of empty editor groups.")); export const EDITOR_GROUP_EMPTY_BACKGROUND = registerColor('editorGroup.emptyBackground', { dark: null, light: null, hc: null -}, nls.localize('editorGroupEmptyBackground', "Background color of an empty editor group. Editor groups are the containers of editors.")); +}, localize('editorGroupEmptyBackground', "Background color of an empty editor group. Editor groups are the containers of editors.")); export const EDITOR_GROUP_FOCUSED_EMPTY_BORDER = registerColor('editorGroup.focusedEmptyBorder', { dark: null, light: null, hc: focusBorder -}, nls.localize('editorGroupFocusedEmptyBorder', "Border color of an empty editor group that is focused. Editor groups are the containers of editors.")); +}, localize('editorGroupFocusedEmptyBorder', "Border color of an empty editor group that is focused. Editor groups are the containers of editors.")); export const EDITOR_GROUP_HEADER_TABS_BACKGROUND = registerColor('editorGroupHeader.tabsBackground', { dark: '#252526', light: '#F3F3F3', hc: null -}, nls.localize('tabsContainerBackground', "Background color of the editor group title header when tabs are enabled. Editor groups are the containers of editors.")); +}, localize('tabsContainerBackground', "Background color of the editor group title header when tabs are enabled. Editor groups are the containers of editors.")); export const EDITOR_GROUP_HEADER_TABS_BORDER = registerColor('editorGroupHeader.tabsBorder', { dark: null, light: null, hc: null -}, nls.localize('tabsContainerBorder', "Border color of the editor group title header when tabs are enabled. Editor groups are the containers of editors.")); +}, localize('tabsContainerBorder', "Border color of the editor group title header when tabs are enabled. Editor groups are the containers of editors.")); export const EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND = registerColor('editorGroupHeader.noTabsBackground', { dark: editorBackground, light: editorBackground, hc: editorBackground -}, nls.localize('editorGroupHeaderBackground', "Background color of the editor group title header when tabs are disabled (`\"workbench.editor.showTabs\": false`). Editor groups are the containers of editors.")); +}, localize('editorGroupHeaderBackground', "Background color of the editor group title header when tabs are disabled (`\"workbench.editor.showTabs\": false`). Editor groups are the containers of editors.")); export const EDITOR_GROUP_HEADER_BORDER = registerColor('editorGroupHeader.border', { dark: null, light: null, hc: contrastBorder -}, nls.localize('editorTitleContainerBorder', "Border color of the editor group title header. Editor groups are the containers of editors.")); +}, localize('editorTitleContainerBorder', "Border color of the editor group title header. Editor groups are the containers of editors.")); export const EDITOR_GROUP_BORDER = registerColor('editorGroup.border', { dark: '#444444', light: '#E7E7E7', hc: contrastBorder -}, nls.localize('editorGroupBorder', "Color to separate multiple editor groups from each other. Editor groups are the containers of editors.")); +}, localize('editorGroupBorder', "Color to separate multiple editor groups from each other. Editor groups are the containers of editors.")); export const EDITOR_DRAG_AND_DROP_BACKGROUND = registerColor('editorGroup.dropBackground', { dark: Color.fromHex('#53595D').transparent(0.5), light: Color.fromHex('#2677CB').transparent(0.18), hc: null -}, nls.localize('editorDragAndDropBackground', "Background color when dragging editors around. The color should have transparency so that the editor contents can still shine through.")); +}, localize('editorDragAndDropBackground', "Background color when dragging editors around. The color should have transparency so that the editor contents can still shine through.")); // < --- Resource Viewer --- > @@ -255,7 +255,7 @@ export const IMAGE_PREVIEW_BORDER = registerColor('imagePreview.border', { dark: Color.fromHex('#808080').transparent(0.35), light: Color.fromHex('#808080').transparent(0.35), hc: contrastBorder -}, nls.localize('imagePreviewBorder', "Border color for image in image preview.")); +}, localize('imagePreviewBorder', "Border color for image in image preview.")); // < --- Panels --- > @@ -263,74 +263,74 @@ export const PANEL_BACKGROUND = registerColor('panel.background', { dark: editorBackground, light: editorBackground, hc: editorBackground -}, nls.localize('panelBackground', "Panel background color. Panels are shown below the editor area and contain views like output and integrated terminal.")); +}, localize('panelBackground', "Panel background color. Panels are shown below the editor area and contain views like output and integrated terminal.")); export const PANEL_BORDER = registerColor('panel.border', { dark: Color.fromHex('#808080').transparent(0.35), light: Color.fromHex('#808080').transparent(0.35), hc: contrastBorder -}, nls.localize('panelBorder', "Panel border color to separate the panel from the editor. Panels are shown below the editor area and contain views like output and integrated terminal.")); +}, localize('panelBorder', "Panel border color to separate the panel from the editor. Panels are shown below the editor area and contain views like output and integrated terminal.")); export const PANEL_ACTIVE_TITLE_FOREGROUND = registerColor('panelTitle.activeForeground', { dark: '#E7E7E7', light: '#424242', hc: Color.white -}, nls.localize('panelActiveTitleForeground', "Title color for the active panel. Panels are shown below the editor area and contain views like output and integrated terminal.")); +}, localize('panelActiveTitleForeground', "Title color for the active panel. Panels are shown below the editor area and contain views like output and integrated terminal.")); export const PANEL_INACTIVE_TITLE_FOREGROUND = registerColor('panelTitle.inactiveForeground', { dark: transparent(PANEL_ACTIVE_TITLE_FOREGROUND, 0.6), light: transparent(PANEL_ACTIVE_TITLE_FOREGROUND, 0.75), hc: Color.white -}, nls.localize('panelInactiveTitleForeground', "Title color for the inactive panel. Panels are shown below the editor area and contain views like output and integrated terminal.")); +}, localize('panelInactiveTitleForeground', "Title color for the inactive panel. Panels are shown below the editor area and contain views like output and integrated terminal.")); export const PANEL_ACTIVE_TITLE_BORDER = registerColor('panelTitle.activeBorder', { dark: PANEL_ACTIVE_TITLE_FOREGROUND, light: PANEL_ACTIVE_TITLE_FOREGROUND, hc: contrastBorder -}, nls.localize('panelActiveTitleBorder', "Border color for the active panel title. Panels are shown below the editor area and contain views like output and integrated terminal.")); +}, localize('panelActiveTitleBorder', "Border color for the active panel title. Panels are shown below the editor area and contain views like output and integrated terminal.")); export const PANEL_INPUT_BORDER = registerColor('panelInput.border', { dark: null, light: Color.fromHex('#ddd'), hc: null -}, nls.localize('panelInputBorder', "Input box border for inputs in the panel.")); +}, localize('panelInputBorder', "Input box border for inputs in the panel.")); export const PANEL_DRAG_AND_DROP_BORDER = registerColor('panel.dropBorder', { dark: PANEL_ACTIVE_TITLE_FOREGROUND, light: PANEL_ACTIVE_TITLE_FOREGROUND, hc: PANEL_ACTIVE_TITLE_FOREGROUND, -}, nls.localize('panelDragAndDropBorder', "Drag and drop feedback color for the panel titles. Panels are shown below the editor area and contain views like output and integrated terminal.")); +}, localize('panelDragAndDropBorder', "Drag and drop feedback color for the panel titles. Panels are shown below the editor area and contain views like output and integrated terminal.")); export const PANEL_SECTION_DRAG_AND_DROP_BACKGROUND = registerColor('panelSection.dropBackground', { dark: EDITOR_DRAG_AND_DROP_BACKGROUND, light: EDITOR_DRAG_AND_DROP_BACKGROUND, hc: EDITOR_DRAG_AND_DROP_BACKGROUND, -}, nls.localize('panelSectionDragAndDropBackground', "Drag and drop feedback color for the panel sections. The color should have transparency so that the panel sections can still shine through. Panels are shown below the editor area and contain views like output and integrated terminal. Panel sections are views nested within the panels.")); +}, localize('panelSectionDragAndDropBackground', "Drag and drop feedback color for the panel sections. The color should have transparency so that the panel sections can still shine through. Panels are shown below the editor area and contain views like output and integrated terminal. Panel sections are views nested within the panels.")); export const PANEL_SECTION_HEADER_BACKGROUND = registerColor('panelSectionHeader.background', { dark: Color.fromHex('#808080').transparent(0.2), light: Color.fromHex('#808080').transparent(0.2), hc: null -}, nls.localize('panelSectionHeaderBackground', "Panel section header background color. Panels are shown below the editor area and contain views like output and integrated terminal. Panel sections are views nested within the panels.")); +}, localize('panelSectionHeaderBackground', "Panel section header background color. Panels are shown below the editor area and contain views like output and integrated terminal. Panel sections are views nested within the panels.")); export const PANEL_SECTION_HEADER_FOREGROUND = registerColor('panelSectionHeader.foreground', { dark: null, light: null, hc: null -}, nls.localize('panelSectionHeaderForeground', "Panel section header foreground color. Panels are shown below the editor area and contain views like output and integrated terminal. Panel sections are views nested within the panels.")); +}, localize('panelSectionHeaderForeground', "Panel section header foreground color. Panels are shown below the editor area and contain views like output and integrated terminal. Panel sections are views nested within the panels.")); export const PANEL_SECTION_HEADER_BORDER = registerColor('panelSectionHeader.border', { dark: contrastBorder, light: contrastBorder, hc: contrastBorder -}, nls.localize('panelSectionHeaderBorder', "Panel section header border color used when multiple views are stacked vertically in the panel. Panels are shown below the editor area and contain views like output and integrated terminal. Panel sections are views nested within the panels.")); +}, localize('panelSectionHeaderBorder', "Panel section header border color used when multiple views are stacked vertically in the panel. Panels are shown below the editor area and contain views like output and integrated terminal. Panel sections are views nested within the panels.")); export const PANEL_SECTION_BORDER = registerColor('panelSection.border', { dark: PANEL_BORDER, light: PANEL_BORDER, hc: PANEL_BORDER -}, nls.localize('panelSectionBorder', "Panel section border color used when multiple views are stacked horizontally in the panel. Panels are shown below the editor area and contain views like output and integrated terminal. Panel sections are views nested within the panels.")); +}, localize('panelSectionBorder', "Panel section border color used when multiple views are stacked horizontally in the panel. Panels are shown below the editor area and contain views like output and integrated terminal. Panel sections are views nested within the panels.")); // < --- Status --- > @@ -339,79 +339,79 @@ export const STATUS_BAR_FOREGROUND = registerColor('statusBar.foreground', { dark: '#FFFFFF', light: '#FFFFFF', hc: '#FFFFFF' -}, nls.localize('statusBarForeground', "Status bar foreground color when a workspace or folder is opened. The status bar is shown in the bottom of the window.")); +}, localize('statusBarForeground', "Status bar foreground color when a workspace or folder is opened. The status bar is shown in the bottom of the window.")); export const STATUS_BAR_NO_FOLDER_FOREGROUND = registerColor('statusBar.noFolderForeground', { dark: STATUS_BAR_FOREGROUND, light: STATUS_BAR_FOREGROUND, hc: STATUS_BAR_FOREGROUND -}, nls.localize('statusBarNoFolderForeground', "Status bar foreground color when no folder is opened. The status bar is shown in the bottom of the window.")); +}, localize('statusBarNoFolderForeground', "Status bar foreground color when no folder is opened. The status bar is shown in the bottom of the window.")); export const STATUS_BAR_BACKGROUND = registerColor('statusBar.background', { dark: '#007ACC', light: '#007ACC', hc: null -}, nls.localize('statusBarBackground', "Status bar background color when a workspace or folder is opened. The status bar is shown in the bottom of the window.")); +}, localize('statusBarBackground', "Status bar background color when a workspace or folder is opened. The status bar is shown in the bottom of the window.")); export const STATUS_BAR_NO_FOLDER_BACKGROUND = registerColor('statusBar.noFolderBackground', { dark: '#68217A', light: '#68217A', hc: null -}, nls.localize('statusBarNoFolderBackground', "Status bar background color when no folder is opened. The status bar is shown in the bottom of the window.")); +}, localize('statusBarNoFolderBackground', "Status bar background color when no folder is opened. The status bar is shown in the bottom of the window.")); export const STATUS_BAR_BORDER = registerColor('statusBar.border', { dark: null, light: null, hc: contrastBorder -}, nls.localize('statusBarBorder', "Status bar border color separating to the sidebar and editor. The status bar is shown in the bottom of the window.")); +}, localize('statusBarBorder', "Status bar border color separating to the sidebar and editor. The status bar is shown in the bottom of the window.")); export const STATUS_BAR_NO_FOLDER_BORDER = registerColor('statusBar.noFolderBorder', { dark: STATUS_BAR_BORDER, light: STATUS_BAR_BORDER, hc: STATUS_BAR_BORDER -}, nls.localize('statusBarNoFolderBorder', "Status bar border color separating to the sidebar and editor when no folder is opened. The status bar is shown in the bottom of the window.")); +}, localize('statusBarNoFolderBorder', "Status bar border color separating to the sidebar and editor when no folder is opened. The status bar is shown in the bottom of the window.")); export const STATUS_BAR_ITEM_ACTIVE_BACKGROUND = registerColor('statusBarItem.activeBackground', { dark: Color.white.transparent(0.18), light: Color.white.transparent(0.18), hc: Color.white.transparent(0.18) -}, nls.localize('statusBarItemActiveBackground', "Status bar item background color when clicking. The status bar is shown in the bottom of the window.")); +}, localize('statusBarItemActiveBackground', "Status bar item background color when clicking. The status bar is shown in the bottom of the window.")); export const STATUS_BAR_ITEM_HOVER_BACKGROUND = registerColor('statusBarItem.hoverBackground', { dark: Color.white.transparent(0.12), light: Color.white.transparent(0.12), hc: Color.white.transparent(0.12) -}, nls.localize('statusBarItemHoverBackground', "Status bar item background color when hovering. The status bar is shown in the bottom of the window.")); +}, localize('statusBarItemHoverBackground', "Status bar item background color when hovering. The status bar is shown in the bottom of the window.")); export const STATUS_BAR_PROMINENT_ITEM_FOREGROUND = registerColor('statusBarItem.prominentForeground', { dark: STATUS_BAR_FOREGROUND, light: STATUS_BAR_FOREGROUND, hc: STATUS_BAR_FOREGROUND -}, nls.localize('statusBarProminentItemForeground', "Status bar prominent items foreground color. Prominent items stand out from other status bar entries to indicate importance. Change mode `Toggle Tab Key Moves Focus` from command palette to see an example. The status bar is shown in the bottom of the window.")); +}, localize('statusBarProminentItemForeground', "Status bar prominent items foreground color. Prominent items stand out from other status bar entries to indicate importance. Change mode `Toggle Tab Key Moves Focus` from command palette to see an example. The status bar is shown in the bottom of the window.")); export const STATUS_BAR_PROMINENT_ITEM_BACKGROUND = registerColor('statusBarItem.prominentBackground', { dark: Color.black.transparent(0.5), light: Color.black.transparent(0.5), hc: Color.black.transparent(0.5), -}, nls.localize('statusBarProminentItemBackground', "Status bar prominent items background color. Prominent items stand out from other status bar entries to indicate importance. Change mode `Toggle Tab Key Moves Focus` from command palette to see an example. The status bar is shown in the bottom of the window.")); +}, localize('statusBarProminentItemBackground', "Status bar prominent items background color. Prominent items stand out from other status bar entries to indicate importance. Change mode `Toggle Tab Key Moves Focus` from command palette to see an example. The status bar is shown in the bottom of the window.")); export const STATUS_BAR_PROMINENT_ITEM_HOVER_BACKGROUND = registerColor('statusBarItem.prominentHoverBackground', { dark: Color.black.transparent(0.3), light: Color.black.transparent(0.3), hc: Color.black.transparent(0.3), -}, nls.localize('statusBarProminentItemHoverBackground', "Status bar prominent items background color when hovering. Prominent items stand out from other status bar entries to indicate importance. Change mode `Toggle Tab Key Moves Focus` from command palette to see an example. The status bar is shown in the bottom of the window.")); +}, localize('statusBarProminentItemHoverBackground', "Status bar prominent items background color when hovering. Prominent items stand out from other status bar entries to indicate importance. Change mode `Toggle Tab Key Moves Focus` from command palette to see an example. The status bar is shown in the bottom of the window.")); export const STATUS_BAR_ERROR_ITEM_BACKGROUND = registerColor('statusBarItem.errorBackground', { dark: darken(errorForeground, .4), light: darken(errorForeground, .4), hc: null, -}, nls.localize('statusBarErrorItemBackground', "Status bar error items background color. Error items stand out from other status bar entries to indicate error conditions. The status bar is shown in the bottom of the window.")); +}, localize('statusBarErrorItemBackground', "Status bar error items background color. Error items stand out from other status bar entries to indicate error conditions. The status bar is shown in the bottom of the window.")); export const STATUS_BAR_ERROR_ITEM_FOREGROUND = registerColor('statusBarItem.errorForeground', { dark: Color.white, light: Color.white, hc: Color.white, -}, nls.localize('statusBarErrorItemForeground', "Status bar error items foreground color. Error items stand out from other status bar entries to indicate error conditions. The status bar is shown in the bottom of the window.")); +}, localize('statusBarErrorItemForeground', "Status bar error items foreground color. Error items stand out from other status bar entries to indicate error conditions. The status bar is shown in the bottom of the window.")); // < --- Activity Bar --- > @@ -419,61 +419,61 @@ export const ACTIVITY_BAR_BACKGROUND = registerColor('activityBar.background', { dark: '#333333', light: '#2C2C2C', hc: '#000000' -}, nls.localize('activityBarBackground', "Activity bar background color. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); +}, localize('activityBarBackground', "Activity bar background color. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); export const ACTIVITY_BAR_FOREGROUND = registerColor('activityBar.foreground', { dark: Color.white, light: Color.white, hc: Color.white -}, nls.localize('activityBarForeground', "Activity bar item foreground color when it is active. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); +}, localize('activityBarForeground', "Activity bar item foreground color when it is active. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); export const ACTIVITY_BAR_INACTIVE_FOREGROUND = registerColor('activityBar.inactiveForeground', { dark: transparent(ACTIVITY_BAR_FOREGROUND, 0.4), light: transparent(ACTIVITY_BAR_FOREGROUND, 0.4), hc: Color.white -}, nls.localize('activityBarInActiveForeground', "Activity bar item foreground color when it is inactive. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); +}, localize('activityBarInActiveForeground', "Activity bar item foreground color when it is inactive. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); export const ACTIVITY_BAR_BORDER = registerColor('activityBar.border', { dark: null, light: null, hc: contrastBorder -}, nls.localize('activityBarBorder', "Activity bar border color separating to the side bar. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); +}, localize('activityBarBorder', "Activity bar border color separating to the side bar. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); export const ACTIVITY_BAR_ACTIVE_BORDER = registerColor('activityBar.activeBorder', { dark: ACTIVITY_BAR_FOREGROUND, light: ACTIVITY_BAR_FOREGROUND, hc: null -}, nls.localize('activityBarActiveBorder', "Activity bar border color for the active item. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); +}, localize('activityBarActiveBorder', "Activity bar border color for the active item. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); export const ACTIVITY_BAR_ACTIVE_FOCUS_BORDER = registerColor('activityBar.activeFocusBorder', { dark: null, light: null, hc: null -}, nls.localize('activityBarActiveFocusBorder', "Activity bar focus border color for the active item. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); +}, localize('activityBarActiveFocusBorder', "Activity bar focus border color for the active item. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); export const ACTIVITY_BAR_ACTIVE_BACKGROUND = registerColor('activityBar.activeBackground', { dark: null, light: null, hc: null -}, nls.localize('activityBarActiveBackground', "Activity bar background color for the active item. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); +}, localize('activityBarActiveBackground', "Activity bar background color for the active item. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); export const ACTIVITY_BAR_DRAG_AND_DROP_BORDER = registerColor('activityBar.dropBorder', { dark: ACTIVITY_BAR_FOREGROUND, light: ACTIVITY_BAR_FOREGROUND, hc: ACTIVITY_BAR_FOREGROUND, -}, nls.localize('activityBarDragAndDropBorder', "Drag and drop feedback color for the activity bar items. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); +}, localize('activityBarDragAndDropBorder', "Drag and drop feedback color for the activity bar items. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); export const ACTIVITY_BAR_BADGE_BACKGROUND = registerColor('activityBarBadge.background', { dark: '#007ACC', light: '#007ACC', hc: '#000000' -}, nls.localize('activityBarBadgeBackground', "Activity notification badge background color. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); +}, localize('activityBarBadgeBackground', "Activity notification badge background color. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); export const ACTIVITY_BAR_BADGE_FOREGROUND = registerColor('activityBarBadge.foreground', { dark: Color.white, light: Color.white, hc: Color.white -}, nls.localize('activityBarBadgeForeground', "Activity notification badge foreground color. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); +}, localize('activityBarBadgeForeground', "Activity notification badge foreground color. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); // < --- Remote --- > @@ -482,25 +482,25 @@ export const STATUS_BAR_HOST_NAME_BACKGROUND = registerColor('statusBarItem.remo dark: ACTIVITY_BAR_BADGE_BACKGROUND, light: ACTIVITY_BAR_BADGE_BACKGROUND, hc: ACTIVITY_BAR_BADGE_BACKGROUND -}, nls.localize('statusBarItemHostBackground', "Background color for the remote indicator on the status bar.")); +}, localize('statusBarItemHostBackground', "Background color for the remote indicator on the status bar.")); export const STATUS_BAR_HOST_NAME_FOREGROUND = registerColor('statusBarItem.remoteForeground', { dark: ACTIVITY_BAR_BADGE_FOREGROUND, light: ACTIVITY_BAR_BADGE_FOREGROUND, hc: ACTIVITY_BAR_BADGE_FOREGROUND -}, nls.localize('statusBarItemHostForeground', "Foreground color for the remote indicator on the status bar.")); +}, localize('statusBarItemHostForeground', "Foreground color for the remote indicator on the status bar.")); export const EXTENSION_BADGE_REMOTE_BACKGROUND = registerColor('extensionBadge.remoteBackground', { dark: ACTIVITY_BAR_BADGE_BACKGROUND, light: ACTIVITY_BAR_BADGE_BACKGROUND, hc: ACTIVITY_BAR_BADGE_BACKGROUND -}, nls.localize('extensionBadge.remoteBackground', "Background color for the remote badge in the extensions view.")); +}, localize('extensionBadge.remoteBackground', "Background color for the remote badge in the extensions view.")); export const EXTENSION_BADGE_REMOTE_FOREGROUND = registerColor('extensionBadge.remoteForeground', { dark: ACTIVITY_BAR_BADGE_FOREGROUND, light: ACTIVITY_BAR_BADGE_FOREGROUND, hc: ACTIVITY_BAR_BADGE_FOREGROUND -}, nls.localize('extensionBadge.remoteForeground', "Foreground color for the remote badge in the extensions view.")); +}, localize('extensionBadge.remoteForeground', "Foreground color for the remote badge in the extensions view.")); // < --- Side Bar --- > @@ -509,49 +509,49 @@ export const SIDE_BAR_BACKGROUND = registerColor('sideBar.background', { dark: '#252526', light: '#F3F3F3', hc: '#000000' -}, nls.localize('sideBarBackground', "Side bar background color. The side bar is the container for views like explorer and search.")); +}, localize('sideBarBackground', "Side bar background color. The side bar is the container for views like explorer and search.")); export const SIDE_BAR_FOREGROUND = registerColor('sideBar.foreground', { dark: null, light: null, hc: null -}, nls.localize('sideBarForeground', "Side bar foreground color. The side bar is the container for views like explorer and search.")); +}, localize('sideBarForeground', "Side bar foreground color. The side bar is the container for views like explorer and search.")); export const SIDE_BAR_BORDER = registerColor('sideBar.border', { dark: null, light: null, hc: contrastBorder -}, nls.localize('sideBarBorder', "Side bar border color on the side separating to the editor. The side bar is the container for views like explorer and search.")); +}, localize('sideBarBorder', "Side bar border color on the side separating to the editor. The side bar is the container for views like explorer and search.")); export const SIDE_BAR_TITLE_FOREGROUND = registerColor('sideBarTitle.foreground', { dark: SIDE_BAR_FOREGROUND, light: SIDE_BAR_FOREGROUND, hc: SIDE_BAR_FOREGROUND -}, nls.localize('sideBarTitleForeground', "Side bar title foreground color. The side bar is the container for views like explorer and search.")); +}, localize('sideBarTitleForeground', "Side bar title foreground color. The side bar is the container for views like explorer and search.")); export const SIDE_BAR_DRAG_AND_DROP_BACKGROUND = registerColor('sideBar.dropBackground', { dark: EDITOR_DRAG_AND_DROP_BACKGROUND, light: EDITOR_DRAG_AND_DROP_BACKGROUND, hc: EDITOR_DRAG_AND_DROP_BACKGROUND, -}, nls.localize('sideBarDragAndDropBackground', "Drag and drop feedback color for the side bar sections. The color should have transparency so that the side bar sections can still shine through. The side bar is the container for views like explorer and search. Side bar sections are views nested within the side bar.")); +}, localize('sideBarDragAndDropBackground', "Drag and drop feedback color for the side bar sections. The color should have transparency so that the side bar sections can still shine through. The side bar is the container for views like explorer and search. Side bar sections are views nested within the side bar.")); export const SIDE_BAR_SECTION_HEADER_BACKGROUND = registerColor('sideBarSectionHeader.background', { dark: Color.fromHex('#808080').transparent(0.2), light: Color.fromHex('#808080').transparent(0.2), hc: null -}, nls.localize('sideBarSectionHeaderBackground', "Side bar section header background color. The side bar is the container for views like explorer and search. Side bar sections are views nested within the side bar.")); +}, localize('sideBarSectionHeaderBackground', "Side bar section header background color. The side bar is the container for views like explorer and search. Side bar sections are views nested within the side bar.")); export const SIDE_BAR_SECTION_HEADER_FOREGROUND = registerColor('sideBarSectionHeader.foreground', { dark: SIDE_BAR_FOREGROUND, light: SIDE_BAR_FOREGROUND, hc: SIDE_BAR_FOREGROUND -}, nls.localize('sideBarSectionHeaderForeground', "Side bar section header foreground color. The side bar is the container for views like explorer and search. Side bar sections are views nested within the side bar.")); +}, localize('sideBarSectionHeaderForeground', "Side bar section header foreground color. The side bar is the container for views like explorer and search. Side bar sections are views nested within the side bar.")); export const SIDE_BAR_SECTION_HEADER_BORDER = registerColor('sideBarSectionHeader.border', { dark: contrastBorder, light: contrastBorder, hc: contrastBorder -}, nls.localize('sideBarSectionHeaderBorder', "Side bar section header border color. The side bar is the container for views like explorer and search. Side bar sections are views nested within the side bar.")); +}, localize('sideBarSectionHeaderBorder', "Side bar section header border color. The side bar is the container for views like explorer and search. Side bar sections are views nested within the side bar.")); // < --- Title Bar --- > @@ -560,31 +560,31 @@ export const TITLE_BAR_ACTIVE_FOREGROUND = registerColor('titleBar.activeForegro dark: '#CCCCCC', light: '#333333', hc: '#FFFFFF' -}, nls.localize('titleBarActiveForeground', "Title bar foreground when the window is active.")); +}, localize('titleBarActiveForeground', "Title bar foreground when the window is active.")); export const TITLE_BAR_INACTIVE_FOREGROUND = registerColor('titleBar.inactiveForeground', { dark: transparent(TITLE_BAR_ACTIVE_FOREGROUND, 0.6), light: transparent(TITLE_BAR_ACTIVE_FOREGROUND, 0.6), hc: null -}, nls.localize('titleBarInactiveForeground', "Title bar foreground when the window is inactive.")); +}, localize('titleBarInactiveForeground', "Title bar foreground when the window is inactive.")); export const TITLE_BAR_ACTIVE_BACKGROUND = registerColor('titleBar.activeBackground', { dark: '#3C3C3C', light: '#DDDDDD', hc: '#000000' -}, nls.localize('titleBarActiveBackground', "Title bar background when the window is active.")); +}, localize('titleBarActiveBackground', "Title bar background when the window is active.")); export const TITLE_BAR_INACTIVE_BACKGROUND = registerColor('titleBar.inactiveBackground', { dark: transparent(TITLE_BAR_ACTIVE_BACKGROUND, 0.6), light: transparent(TITLE_BAR_ACTIVE_BACKGROUND, 0.6), hc: null -}, nls.localize('titleBarInactiveBackground', "Title bar background when the window is inactive.")); +}, localize('titleBarInactiveBackground', "Title bar background when the window is inactive.")); export const TITLE_BAR_BORDER = registerColor('titleBar.border', { dark: null, light: null, hc: contrastBorder -}, nls.localize('titleBarBorder', "Title bar border color.")); +}, localize('titleBarBorder', "Title bar border color.")); // < --- Menubar --- > @@ -592,19 +592,19 @@ export const MENUBAR_SELECTION_FOREGROUND = registerColor('menubar.selectionFore dark: TITLE_BAR_ACTIVE_FOREGROUND, light: TITLE_BAR_ACTIVE_FOREGROUND, hc: TITLE_BAR_ACTIVE_FOREGROUND -}, nls.localize('menubarSelectionForeground', "Foreground color of the selected menu item in the menubar.")); +}, localize('menubarSelectionForeground', "Foreground color of the selected menu item in the menubar.")); export const MENUBAR_SELECTION_BACKGROUND = registerColor('menubar.selectionBackground', { dark: transparent(Color.white, 0.1), light: transparent(Color.black, 0.1), hc: null -}, nls.localize('menubarSelectionBackground', "Background color of the selected menu item in the menubar.")); +}, localize('menubarSelectionBackground', "Background color of the selected menu item in the menubar.")); export const MENUBAR_SELECTION_BORDER = registerColor('menubar.selectionBorder', { dark: null, light: null, hc: activeContrastBorder -}, nls.localize('menubarSelectionBorder', "Border color of the selected menu item in the menubar.")); +}, localize('menubarSelectionBorder', "Border color of the selected menu item in the menubar.")); // < --- Notifications --- > @@ -612,76 +612,76 @@ export const NOTIFICATIONS_CENTER_BORDER = registerColor('notificationCenter.bor dark: null, light: null, hc: contrastBorder -}, nls.localize('notificationCenterBorder', "Notifications center border color. Notifications slide in from the bottom right of the window.")); +}, localize('notificationCenterBorder', "Notifications center border color. Notifications slide in from the bottom right of the window.")); export const NOTIFICATIONS_TOAST_BORDER = registerColor('notificationToast.border', { dark: null, light: null, hc: contrastBorder -}, nls.localize('notificationToastBorder', "Notification toast border color. Notifications slide in from the bottom right of the window.")); +}, localize('notificationToastBorder', "Notification toast border color. Notifications slide in from the bottom right of the window.")); export const NOTIFICATIONS_FOREGROUND = registerColor('notifications.foreground', { dark: editorWidgetForeground, light: editorWidgetForeground, hc: editorWidgetForeground -}, nls.localize('notificationsForeground', "Notifications foreground color. Notifications slide in from the bottom right of the window.")); +}, localize('notificationsForeground', "Notifications foreground color. Notifications slide in from the bottom right of the window.")); export const NOTIFICATIONS_BACKGROUND = registerColor('notifications.background', { dark: editorWidgetBackground, light: editorWidgetBackground, hc: editorWidgetBackground -}, nls.localize('notificationsBackground', "Notifications background color. Notifications slide in from the bottom right of the window.")); +}, localize('notificationsBackground', "Notifications background color. Notifications slide in from the bottom right of the window.")); export const NOTIFICATIONS_LINKS = registerColor('notificationLink.foreground', { dark: textLinkForeground, light: textLinkForeground, hc: textLinkForeground -}, nls.localize('notificationsLink', "Notification links foreground color. Notifications slide in from the bottom right of the window.")); +}, localize('notificationsLink', "Notification links foreground color. Notifications slide in from the bottom right of the window.")); export const NOTIFICATIONS_CENTER_HEADER_FOREGROUND = registerColor('notificationCenterHeader.foreground', { dark: null, light: null, hc: null -}, nls.localize('notificationCenterHeaderForeground', "Notifications center header foreground color. Notifications slide in from the bottom right of the window.")); +}, localize('notificationCenterHeaderForeground', "Notifications center header foreground color. Notifications slide in from the bottom right of the window.")); export const NOTIFICATIONS_CENTER_HEADER_BACKGROUND = registerColor('notificationCenterHeader.background', { dark: lighten(NOTIFICATIONS_BACKGROUND, 0.3), light: darken(NOTIFICATIONS_BACKGROUND, 0.05), hc: NOTIFICATIONS_BACKGROUND -}, nls.localize('notificationCenterHeaderBackground', "Notifications center header background color. Notifications slide in from the bottom right of the window.")); +}, localize('notificationCenterHeaderBackground', "Notifications center header background color. Notifications slide in from the bottom right of the window.")); export const NOTIFICATIONS_BORDER = registerColor('notifications.border', { dark: NOTIFICATIONS_CENTER_HEADER_BACKGROUND, light: NOTIFICATIONS_CENTER_HEADER_BACKGROUND, hc: NOTIFICATIONS_CENTER_HEADER_BACKGROUND -}, nls.localize('notificationsBorder', "Notifications border color separating from other notifications in the notifications center. Notifications slide in from the bottom right of the window.")); +}, localize('notificationsBorder', "Notifications border color separating from other notifications in the notifications center. Notifications slide in from the bottom right of the window.")); export const NOTIFICATIONS_ERROR_ICON_FOREGROUND = registerColor('notificationsErrorIcon.foreground', { dark: editorErrorForeground, light: editorErrorForeground, hc: editorErrorForeground -}, nls.localize('notificationsErrorIconForeground', "The color used for the icon of error notifications. Notifications slide in from the bottom right of the window.")); +}, localize('notificationsErrorIconForeground', "The color used for the icon of error notifications. Notifications slide in from the bottom right of the window.")); export const NOTIFICATIONS_WARNING_ICON_FOREGROUND = registerColor('notificationsWarningIcon.foreground', { dark: editorWarningForeground, light: editorWarningForeground, hc: editorWarningForeground -}, nls.localize('notificationsWarningIconForeground', "The color used for the icon of warning notifications. Notifications slide in from the bottom right of the window.")); +}, localize('notificationsWarningIconForeground', "The color used for the icon of warning notifications. Notifications slide in from the bottom right of the window.")); export const NOTIFICATIONS_INFO_ICON_FOREGROUND = registerColor('notificationsInfoIcon.foreground', { dark: editorInfoForeground, light: editorInfoForeground, hc: editorInfoForeground -}, nls.localize('notificationsInfoIconForeground', "The color used for the icon of info notifications. Notifications slide in from the bottom right of the window.")); +}, localize('notificationsInfoIconForeground', "The color used for the icon of info notifications. Notifications slide in from the bottom right of the window.")); export const WINDOW_ACTIVE_BORDER = registerColor('window.activeBorder', { dark: null, light: null, hc: contrastBorder -}, nls.localize('windowActiveBorder', "The color used for the border of the window when it is active. Only supported in the desktop client when using the custom title bar.")); +}, localize('windowActiveBorder', "The color used for the border of the window when it is active. Only supported in the desktop client when using the custom title bar.")); export const WINDOW_INACTIVE_BORDER = registerColor('window.inactiveBorder', { dark: null, light: null, hc: contrastBorder -}, nls.localize('windowInactiveBorder', "The color used for the border of the window when it is inactive. Only supported in the desktop client when using the custom title bar.")); +}, localize('windowInactiveBorder', "The color used for the border of the window when it is inactive. Only supported in the desktop client when using the custom title bar.")); diff --git a/src/vs/workbench/electron-sandbox/actions/windowActions.ts b/src/vs/workbench/electron-sandbox/actions/windowActions.ts index f153e787029..c6567c33e06 100644 --- a/src/vs/workbench/electron-sandbox/actions/windowActions.ts +++ b/src/vs/workbench/electron-sandbox/actions/windowActions.ts @@ -6,7 +6,7 @@ import 'vs/css!./media/actions'; import { URI } from 'vs/base/common/uri'; import { Action } from 'vs/base/common/actions'; -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { applyZoom } from 'vs/platform/windows/electron-sandbox/window'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { getZoomLevel } from 'vs/base/browser/browser'; @@ -25,7 +25,7 @@ import { isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/pla export class CloseCurrentWindowAction extends Action { static readonly ID = 'workbench.action.closeWindow'; - static readonly LABEL = nls.localize('closeWindow', "Close Window"); + static readonly LABEL = localize('closeWindow', "Close Window"); constructor( id: string, @@ -71,7 +71,7 @@ export abstract class BaseZoomAction extends Action { export class ZoomInAction extends BaseZoomAction { static readonly ID = 'workbench.action.zoomIn'; - static readonly LABEL = nls.localize('zoomIn', "Zoom In"); + static readonly LABEL = localize('zoomIn', "Zoom In"); constructor( id: string, @@ -89,7 +89,7 @@ export class ZoomInAction extends BaseZoomAction { export class ZoomOutAction extends BaseZoomAction { static readonly ID = 'workbench.action.zoomOut'; - static readonly LABEL = nls.localize('zoomOut', "Zoom Out"); + static readonly LABEL = localize('zoomOut', "Zoom Out"); constructor( id: string, @@ -107,7 +107,7 @@ export class ZoomOutAction extends BaseZoomAction { export class ZoomResetAction extends BaseZoomAction { static readonly ID = 'workbench.action.zoomReset'; - static readonly LABEL = nls.localize('zoomReset', "Reset Zoom"); + static readonly LABEL = localize('zoomReset', "Reset Zoom"); constructor( id: string, @@ -126,12 +126,12 @@ export abstract class BaseSwitchWindow extends Action { private readonly closeWindowAction: IQuickInputButton = { iconClass: Codicon.removeClose.classNames, - tooltip: nls.localize('close', "Close Window") + tooltip: localize('close', "Close Window") }; private readonly closeDirtyWindowAction: IQuickInputButton = { iconClass: 'dirty-window ' + Codicon.closeDirty, - tooltip: nls.localize('close', "Close Window"), + tooltip: localize('close', "Close Window"), alwaysVisible: true }; @@ -153,16 +153,16 @@ export abstract class BaseSwitchWindow extends Action { const currentWindowId = this.nativeHostService.windowId; const windows = await this.nativeHostService.getWindows(); - const placeHolder = nls.localize('switchWindowPlaceHolder', "Select a window to switch to"); + const placeHolder = localize('switchWindowPlaceHolder', "Select a window to switch to"); const picks = windows.map(window => { const resource = window.filename ? URI.file(window.filename) : isSingleFolderWorkspaceIdentifier(window.workspace) ? window.workspace.uri : isWorkspaceIdentifier(window.workspace) ? window.workspace.configPath : undefined; const fileKind = window.filename ? FileKind.FILE : isSingleFolderWorkspaceIdentifier(window.workspace) ? FileKind.FOLDER : isWorkspaceIdentifier(window.workspace) ? FileKind.ROOT_FOLDER : FileKind.FILE; return { payload: window.id, label: window.title, - ariaLabel: window.dirty ? nls.localize('windowDirtyAriaLabel', "{0}, dirty window", window.title) : window.title, + ariaLabel: window.dirty ? localize('windowDirtyAriaLabel', "{0}, dirty window", window.title) : window.title, iconClasses: getIconClasses(this.modelService, this.modeService, resource, fileKind), - description: (currentWindowId === window.id) ? nls.localize('current', "Current Window") : undefined, + description: (currentWindowId === window.id) ? localize('current', "Current Window") : undefined, buttons: currentWindowId !== window.id ? window.dirty ? [this.closeDirtyWindowAction] : [this.closeWindowAction] : undefined }; }); @@ -188,7 +188,7 @@ export abstract class BaseSwitchWindow extends Action { export class SwitchWindow extends BaseSwitchWindow { static readonly ID = 'workbench.action.switchWindow'; - static readonly LABEL = nls.localize('switchWindow', "Switch Window..."); + static readonly LABEL = localize('switchWindow', "Switch Window..."); constructor( id: string, @@ -210,7 +210,7 @@ export class SwitchWindow extends BaseSwitchWindow { export class QuickSwitchWindow extends BaseSwitchWindow { static readonly ID = 'workbench.action.quickSwitchWindow'; - static readonly LABEL = nls.localize('quickSwitchWindow', "Quick Switch Window..."); + static readonly LABEL = localize('quickSwitchWindow', "Quick Switch Window..."); constructor( id: string, diff --git a/src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts b/src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts index 6e9b7b93f98..3805a175897 100644 --- a/src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts +++ b/src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { fromNow } from 'vs/base/common/date'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; import { isLinux, isLinuxSnap, isWindows } from 'vs/base/common/platform'; @@ -58,13 +58,13 @@ export class NativeDialogHandler implements IDialogHandler { if (confirmation.primaryButton) { buttons.push(confirmation.primaryButton); } else { - buttons.push(nls.localize({ key: 'yesButton', comment: ['&& denotes a mnemonic'] }, "&&Yes")); + buttons.push(localize({ key: 'yesButton', comment: ['&& denotes a mnemonic'] }, "&&Yes")); } if (confirmation.secondaryButton) { buttons.push(confirmation.secondaryButton); } else if (typeof confirmation.secondaryButton === 'undefined') { - buttons.push(nls.localize('cancelButton', "Cancel")); + buttons.push(localize('cancelButton', "Cancel")); } const opts: MessageBoxOptions = { @@ -166,7 +166,7 @@ export class NativeDialogHandler implements IDialogHandler { const osProps = await this.nativeHostService.getOSProperties(); const detailString = (useAgo: boolean): string => { - return nls.localize({ key: 'aboutDetail', comment: ['Electron, Chrome, Node.js and V8 are product names that need no translation'] }, + return localize({ key: 'aboutDetail', comment: ['Electron, Chrome, Node.js and V8 are product names that need no translation'] }, "Version: {0}\nCommit: {1}\nDate: {2}\nElectron: {3}\nChrome: {4}\nNode.js: {5}\nV8: {6}\nOS: {7}", version, this.productService.commit || 'Unknown', @@ -182,8 +182,8 @@ export class NativeDialogHandler implements IDialogHandler { const detail = detailString(true); const detailToCopy = detailString(false); - const ok = nls.localize('okButton', "OK"); - const copy = mnemonicButtonLabel(nls.localize({ key: 'copy', comment: ['&& denotes a mnemonic'] }, "&&Copy")); + const ok = localize('okButton', "OK"); + const copy = mnemonicButtonLabel(localize({ key: 'copy', comment: ['&& denotes a mnemonic'] }, "&&Copy")); let buttons: string[]; if (isLinux) { buttons = [copy, ok]; diff --git a/src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts b/src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts index c2258de1123..10a7e668c9d 100644 --- a/src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { getZoomFactor } from 'vs/base/browser/browser'; -import * as DOM from 'vs/base/browser/dom'; +import { $, addDisposableListener, append, Dimension, EventType, hide, prepend, runAtThisOrScheduleAtNextAnimationFrame, show } from 'vs/base/browser/dom'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { ILabelService } from 'vs/platform/label/common/label'; @@ -86,9 +86,9 @@ export class TitlebarPart extends BrowserTitleBarPart { if (this.resizer) { if (maximized) { - DOM.hide(this.resizer); + hide(this.resizer); } else { - DOM.show(this.resizer); + show(this.resizer); } } @@ -98,9 +98,9 @@ export class TitlebarPart extends BrowserTitleBarPart { private onMenubarFocusChanged(focused: boolean) { if ((isWindows || isLinux) && this.currentMenubarVisibility !== 'compact' && this.dragRegion) { if (focused) { - DOM.hide(this.dragRegion); + hide(this.dragRegion); } else { - DOM.show(this.dragRegion); + show(this.dragRegion); } } } @@ -110,8 +110,8 @@ export class TitlebarPart extends BrowserTitleBarPart { if ((isWindows || isLinux) && this.currentMenubarVisibility === 'toggle' && visible) { // Hack to fix issue #52522 with layered webkit-app-region elements appearing under cursor if (this.dragRegion) { - DOM.hide(this.dragRegion); - setTimeout(() => DOM.show(this.dragRegion!), 50); + hide(this.dragRegion); + setTimeout(() => show(this.dragRegion!), 50); } } @@ -173,27 +173,27 @@ export class TitlebarPart extends BrowserTitleBarPart { if (this.appIcon) { this.onUpdateAppIconDragBehavior(); - this._register(DOM.addDisposableListener(this.appIcon, DOM.EventType.DBLCLICK, (e => { + this._register(addDisposableListener(this.appIcon, EventType.DBLCLICK, (e => { this.nativeHostService.closeWindow(); }))); } // Draggable region that we can manipulate for #52522 - this.dragRegion = DOM.prepend(this.element, DOM.$('div.titlebar-drag-region')); + this.dragRegion = prepend(this.element, $('div.titlebar-drag-region')); // Window Controls (Native Windows/Linux) if (!isMacintosh) { - this.windowControls = DOM.append(this.element, DOM.$('div.window-controls-container')); + this.windowControls = append(this.element, $('div.window-controls-container')); // Minimize - const minimizeIcon = DOM.append(this.windowControls, DOM.$('div.window-icon.window-minimize' + Codicon.chromeMinimize.cssSelector)); - this._register(DOM.addDisposableListener(minimizeIcon, DOM.EventType.CLICK, e => { + const minimizeIcon = append(this.windowControls, $('div.window-icon.window-minimize' + Codicon.chromeMinimize.cssSelector)); + this._register(addDisposableListener(minimizeIcon, EventType.CLICK, e => { this.nativeHostService.minimizeWindow(); })); // Restore - this.maxRestoreControl = DOM.append(this.windowControls, DOM.$('div.window-icon.window-max-restore')); - this._register(DOM.addDisposableListener(this.maxRestoreControl, DOM.EventType.CLICK, async e => { + this.maxRestoreControl = append(this.windowControls, $('div.window-icon.window-max-restore')); + this._register(addDisposableListener(this.maxRestoreControl, EventType.CLICK, async e => { const maximized = await this.nativeHostService.isMaximized(); if (maximized) { return this.nativeHostService.unmaximizeWindow(); @@ -203,13 +203,13 @@ export class TitlebarPart extends BrowserTitleBarPart { })); // Close - const closeIcon = DOM.append(this.windowControls, DOM.$('div.window-icon.window-close' + Codicon.chromeClose.cssSelector)); - this._register(DOM.addDisposableListener(closeIcon, DOM.EventType.CLICK, e => { + const closeIcon = append(this.windowControls, $('div.window-icon.window-close' + Codicon.chromeClose.cssSelector)); + this._register(addDisposableListener(closeIcon, EventType.CLICK, e => { this.nativeHostService.closeWindow(); })); // Resizer - this.resizer = DOM.append(this.element, DOM.$('div.resizer')); + this.resizer = append(this.element, $('div.resizer')); this._register(this.layoutService.onMaximizeChange(maximized => this.onDidChangeMaximized(maximized))); this.onDidChangeMaximized(this.layoutService.isWindowMaximized()); @@ -218,7 +218,7 @@ export class TitlebarPart extends BrowserTitleBarPart { return ret; } - updateLayout(dimension: DOM.Dimension): void { + updateLayout(dimension: Dimension): void { this.lastLayoutDimensions = dimension; if (getTitleBarStyle(this.configurationService) === 'custom') { @@ -247,10 +247,10 @@ export class TitlebarPart extends BrowserTitleBarPart { } } - DOM.runAtThisOrScheduleAtNextAnimationFrame(() => this.adjustTitleMarginToCenter()); + runAtThisOrScheduleAtNextAnimationFrame(() => this.adjustTitleMarginToCenter()); if (this.customMenubar) { - const menubarDimension = new DOM.Dimension(0, dimension.height); + const menubarDimension = new Dimension(0, dimension.height); this.customMenubar.layout(menubarDimension); } } diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index b99e476e2df..2d1a99a455c 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IResourceEditorInput, ITextEditorOptions, IEditorOptions, EditorActivation } from 'vs/platform/editor/common/editor'; import { SideBySideEditor, IEditorInput, IEditorPane, GroupIdentifier, IFileEditorInput, IUntitledTextResourceEditorInput, IResourceDiffEditorInput, IEditorInputFactoryRegistry, Extensions as EditorExtensions, EditorInput, SideBySideEditorInput, IEditorInputWithOptions, isEditorInputWithOptions, EditorOptions, TextEditorOptions, IEditorIdentifier, IEditorCloseEvent, ITextEditorPane, ITextDiffEditorPane, IRevertOptions, SaveReason, EditorsOrder, isTextEditorPane, IWorkbenchEditorConfiguration, EditorResourceAccessor, IVisibleEditorPane } from 'vs/workbench/common/editor'; @@ -1182,7 +1182,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { infos.forEach(info => { enumValues.push(info.id); - enumDescriptions.push(nls.localize('editorAssociations.viewType.sourceDescription', "Source: {0}", info.providerDisplayName)); + enumDescriptions.push(localize('editorAssociations.viewType.sourceDescription', "Source: {0}", info.providerDisplayName)); }); updateViewTypeSchema(enumValues, enumDescriptions); diff --git a/src/vs/workbench/services/notification/common/notificationService.ts b/src/vs/workbench/services/notification/common/notificationService.ts index 2c52dc75ffe..122f6e79b35 100644 --- a/src/vs/workbench/services/notification/common/notificationService.ts +++ b/src/vs/workbench/services/notification/common/notificationService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { INotificationService, INotification, INotificationHandle, Severity, NotificationMessage, INotificationActions, IPromptChoice, IPromptOptions, IStatusMessageOptions, NoOpNotification, NeverShowAgainScope, NotificationsFilter } from 'vs/platform/notification/common/notification'; import { NotificationsModel, ChoiceAction } from 'vs/workbench/common/notifications'; import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; @@ -75,7 +75,7 @@ export class NotificationService extends Disposable implements INotificationServ const neverShowAgainAction = toDispose.add(new Action( 'workbench.notification.neverShowAgain', - nls.localize('neverShowAgain', "Don't Show Again"), + localize('neverShowAgain', "Don't Show Again"), undefined, true, async () => { // Close notification @@ -123,7 +123,7 @@ export class NotificationService extends Disposable implements INotificationServ } const neverShowAgainChoice = { - label: nls.localize('neverShowAgain', "Don't Show Again"), + label: localize('neverShowAgain', "Don't Show Again"), run: () => this.storageService.store(id, true, scope, StorageTarget.USER), isSecondary: options.neverShowAgain.isSecondary }; diff --git a/src/vs/workbench/services/textfile/browser/textFileService.ts b/src/vs/workbench/services/textfile/browser/textFileService.ts index 8e31df89bb1..9fe5b186c31 100644 --- a/src/vs/workbench/services/textfile/browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { URI } from 'vs/base/common/uri'; import { ITextFileService, ITextFileStreamContent, ITextFileContent, IResourceEncodings, IReadTextFileOptions, IWriteTextFileOptions, toBufferOrReadable, TextFileOperationError, TextFileOperationResult, ITextFileSaveOptions, ITextFileEditorModelManager, IResourceEncoding, stringToSnapshot, ITextFileSaveAsOptions } from 'vs/workbench/services/textfile/common/textfiles'; import { IRevertOptions, IEncodingSupport } from 'vs/workbench/common/editor'; @@ -143,7 +143,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex // validate binary if (options?.acceptTextOnly && decoder.detected.seemsBinary) { - throw new TextFileOperationError(nls.localize('fileBinaryError', "File seems to be binary and cannot be opened as text"), TextFileOperationResult.FILE_IS_BINARY, options); + throw new TextFileOperationError(localize('fileBinaryError', "File seems to be binary and cannot be opened as text"), TextFileOperationResult.FILE_IS_BINARY, options); } return [bufferStream, decoder]; @@ -414,9 +414,9 @@ export abstract class AbstractTextFileService extends Disposable implements ITex private async confirmOverwrite(resource: URI): Promise { const confirm: IConfirmation = { - message: nls.localize('confirmOverwrite', "'{0}' already exists. Do you want to replace it?", basename(resource)), - detail: nls.localize('irreversible', "A file or folder with the name '{0}' already exists in the folder '{1}'. Replacing it will overwrite its current contents.", basename(resource), basename(dirname(resource))), - primaryButton: nls.localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace"), + message: localize('confirmOverwrite', "'{0}' already exists. Do you want to replace it?", basename(resource)), + detail: localize('irreversible', "A file or folder with the name '{0}' already exists in the folder '{1}'. Replacing it will overwrite its current contents.", basename(resource), basename(dirname(resource))), + primaryButton: localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace"), type: 'warning' }; diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index a6f0de819d3..cfde3de4dad 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { Emitter } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; import { assertIsDefined, withNullAsUndefined } from 'vs/base/common/types'; @@ -987,7 +987,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Decode: Load with encoding else { if (this.isDirty()) { - this.notificationService.info(nls.localize('saveFileFirst', "The file is dirty. Please save it first before reopening it with another encoding.")); + this.notificationService.info(localize('saveFileFirst', "The file is dirty. Please save it first before reopening it with another encoding.")); return; } diff --git a/src/vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService.ts b/src/vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService.ts index a851ffe2676..64cd61a6431 100644 --- a/src/vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService.ts +++ b/src/vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService.ts @@ -5,7 +5,7 @@ import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; import { URI } from 'vs/base/common/uri'; -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IJSONEditingService, JSONEditingError, JSONEditingErrorCode } from 'vs/workbench/services/configuration/common/jsonEditing'; import { IWorkspaceIdentifier, IWorkspaceFolderCreationData, IWorkspacesService, rewriteWorkspaceFileForNewLocation, WORKSPACE_FILTER, IEnterWorkspaceResult, hasWorkspaceFileExtension, WORKSPACE_EXTENSION, isUntitledWorkspace, IStoredWorkspace } from 'vs/platform/workspaces/common/workspaces'; @@ -51,8 +51,8 @@ export abstract class AbstractWorkspaceEditingService implements IWorkspaceEditi async pickNewWorkspacePath(): Promise { let workspacePath = await this.fileDialogService.showSaveDialog({ - saveLabel: mnemonicButtonLabel(nls.localize('save', "Save")), - title: nls.localize('saveWorkspace', "Save Workspace"), + saveLabel: mnemonicButtonLabel(localize('save', "Save")), + title: localize('saveWorkspace', "Save Workspace"), filters: WORKSPACE_FILTER, defaultUri: await this.fileDialogService.defaultWorkspacePath(undefined, UNTITLED_WORKSPACE_FILENAME) }); @@ -292,19 +292,19 @@ export abstract class AbstractWorkspaceEditingService implements IWorkspaceEditi } private onInvalidWorkspaceConfigurationFileError(): void { - const message = nls.localize('errorInvalidTaskConfiguration', "Unable to write into workspace configuration file. Please open the file to correct errors/warnings in it and try again."); + const message = localize('errorInvalidTaskConfiguration', "Unable to write into workspace configuration file. Please open the file to correct errors/warnings in it and try again."); this.askToOpenWorkspaceConfigurationFile(message); } private onWorkspaceConfigurationFileDirtyError(): void { - const message = nls.localize('errorWorkspaceConfigurationFileDirty', "Unable to write into workspace configuration file because the file is dirty. Please save it and try again."); + const message = localize('errorWorkspaceConfigurationFileDirty', "Unable to write into workspace configuration file because the file is dirty. Please save it and try again."); this.askToOpenWorkspaceConfigurationFile(message); } private askToOpenWorkspaceConfigurationFile(message: string): void { this.notificationService.prompt(Severity.Error, message, [{ - label: nls.localize('openWorkspaceConfigurationFile', "Open Workspace Configuration"), + label: localize('openWorkspaceConfigurationFile', "Open Workspace Configuration"), run: () => this.commandService.executeCommand('workbench.action.openWorkspaceConfigFile') }] ); From 3b6599f6ba95c6f4cd7e56298a1c646b381ef9ca Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 18 Feb 2021 08:15:51 +0100 Subject: [PATCH 299/325] debt - remove IActionViewItem from composite (#116112) --- src/vs/workbench/common/composite.ts | 7 +------ .../progress/test/browser/progressIndicator.test.ts | 3 +-- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/common/composite.ts b/src/vs/workbench/common/composite.ts index d27f59b3627..b2bd447062c 100644 --- a/src/vs/workbench/common/composite.ts +++ b/src/vs/workbench/common/composite.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IAction, IActionViewItem } from 'vs/base/common/actions'; +import { IAction } from 'vs/base/common/actions'; import { Event } from 'vs/base/common/event'; export interface IComposite { @@ -48,11 +48,6 @@ export interface IComposite { */ getContextMenuActions(): ReadonlyArray; - /** - * Returns the action item for a specific action. - */ - getActionViewItem(action: IAction): IActionViewItem | undefined; - /** * Returns the underlying control of this composite. */ diff --git a/src/vs/workbench/services/progress/test/browser/progressIndicator.test.ts b/src/vs/workbench/services/progress/test/browser/progressIndicator.test.ts index afe18caf17f..e90d4794abe 100644 --- a/src/vs/workbench/services/progress/test/browser/progressIndicator.test.ts +++ b/src/vs/workbench/services/progress/test/browser/progressIndicator.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { IAction, IActionViewItem } from 'vs/base/common/actions'; +import { IAction } from 'vs/base/common/actions'; import { IEditorControl } from 'vs/workbench/common/editor'; import { CompositeScope, CompositeProgressIndicator } from 'vs/workbench/services/progress/browser/progressIndicator'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; @@ -27,7 +27,6 @@ class TestViewlet implements IViewlet { getActions(): IAction[] { return []; } getSecondaryActions(): IAction[] { return []; } getContextMenuActions(): IAction[] { return []; } - getActionViewItem(action: IAction): IActionViewItem { return null!; } getControl(): IEditorControl { return null!; } focus(): void { } getOptimalWidth(): number { return 10; } From eb21069624c0996f8c985b2ab8c5552be83ceff0 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 18 Feb 2021 08:35:19 +0100 Subject: [PATCH 300/325] treeItem.iconPath no longer works with files in globalStorage in Insiders (fix #116735) --- src/vs/code/electron-main/protocol.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vs/code/electron-main/protocol.ts b/src/vs/code/electron-main/protocol.ts index 3e535155c76..298bee5c07b 100644 --- a/src/vs/code/electron-main/protocol.ts +++ b/src/vs/code/electron-main/protocol.ts @@ -31,8 +31,11 @@ export class FileProtocolHandler extends Disposable { // Define an initial set of roots we allow loading from // - appRoot : all files installed as part of the app // - extensions : all files shipped from extensions + // - storage : all files in global and workspace storage (https://github.com/microsoft/vscode/issues/116735) this.validRoots.set(URI.file(environmentService.appRoot), true); this.validRoots.set(URI.file(environmentService.extensionsPath), true); + this.validRoots.set(environmentService.globalStorageHome, true); + this.validRoots.set(environmentService.workspaceStorageHome, true); // Register vscode-file:// handler defaultSession.protocol.registerFileProtocol(Schemas.vscodeFileResource, (request, callback) => this.handleResourceRequest(request, callback as unknown as ProtocolCallback)); From 0f120bfa7cb8624eccc190445c4625f74a2257cc Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 18 Feb 2021 09:20:32 +0100 Subject: [PATCH 301/325] move IActionViewItemProvider and IActionViewItem into its right place, https://github.com/microsoft/vscode/issues/116112#event-4345173898 --- src/vs/base/browser/contextmenu.ts | 3 ++- .../browser/ui/actionbar/actionViewItems.ts | 3 ++- src/vs/base/browser/ui/actionbar/actionbar.ts | 17 +++++++++++++++-- .../ui/dropdown/dropdownActionViewItem.ts | 3 ++- src/vs/base/browser/ui/menu/menu.ts | 4 ++-- src/vs/base/browser/ui/toolbar/toolbar.ts | 4 ++-- src/vs/base/common/actions.ts | 13 ------------- .../contrib/suggest/suggestWidgetStatus.ts | 4 ++-- src/vs/workbench/browser/composite.ts | 3 ++- src/vs/workbench/browser/panecomposite.ts | 3 ++- src/vs/workbench/browser/parts/compositePart.ts | 4 ++-- .../browser/parts/editor/titleControl.ts | 4 ++-- .../workbench/browser/parts/views/treeView.ts | 4 ++-- .../workbench/browser/parts/views/viewPane.ts | 4 ++-- .../browser/parts/views/viewPaneContainer.ts | 3 ++- .../contrib/debug/browser/debugViewlet.ts | 3 ++- src/vs/workbench/contrib/debug/browser/repl.ts | 3 ++- .../contrib/markers/browser/markersView.ts | 4 ++-- .../contrib/output/browser/outputView.ts | 3 ++- .../workbench/contrib/remote/browser/remote.ts | 3 ++- .../scm/browser/scmRepositoryRenderer.ts | 3 ++- .../contrib/scm/browser/scmViewPane.ts | 4 ++-- src/vs/workbench/contrib/scm/browser/util.ts | 4 ++-- .../contrib/terminal/browser/terminalView.ts | 3 ++- .../testing/browser/testingExplorerView.ts | 4 ++-- .../contrib/timeline/browser/timelinePane.ts | 4 ++-- 26 files changed, 63 insertions(+), 51 deletions(-) diff --git a/src/vs/base/browser/contextmenu.ts b/src/vs/base/browser/contextmenu.ts index 2a28dace3c2..49667d70eef 100644 --- a/src/vs/base/browser/contextmenu.ts +++ b/src/vs/base/browser/contextmenu.ts @@ -3,9 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IAction, IActionRunner, IActionViewItem } from 'vs/base/common/actions'; +import { IAction, IActionRunner } from 'vs/base/common/actions'; import { ResolvedKeybinding } from 'vs/base/common/keyCodes'; import { AnchorAlignment, AnchorAxisAlignment } from 'vs/base/browser/ui/contextview/contextview'; +import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; export interface IContextMenuEvent { readonly shiftKey?: boolean; diff --git a/src/vs/base/browser/ui/actionbar/actionViewItems.ts b/src/vs/base/browser/ui/actionbar/actionViewItems.ts index 9abeda1c547..f8cde279f9d 100644 --- a/src/vs/base/browser/ui/actionbar/actionViewItems.ts +++ b/src/vs/base/browser/ui/actionbar/actionViewItems.ts @@ -8,13 +8,14 @@ import * as platform from 'vs/base/common/platform'; import * as nls from 'vs/nls'; import { Disposable } from 'vs/base/common/lifecycle'; import { SelectBox, ISelectOptionItem, ISelectBoxOptions } from 'vs/base/browser/ui/selectBox/selectBox'; -import { IAction, IActionRunner, Action, IActionChangeEvent, ActionRunner, Separator, IActionViewItem } from 'vs/base/common/actions'; +import { IAction, IActionRunner, Action, IActionChangeEvent, ActionRunner, Separator } from 'vs/base/common/actions'; import * as types from 'vs/base/common/types'; import { EventType as TouchEventType, Gesture } from 'vs/base/browser/touch'; import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; import { DataTransfers } from 'vs/base/browser/dnd'; import { isFirefox } from 'vs/base/browser/browser'; import { $, addDisposableListener, append, EventHelper, EventLike, EventType } from 'vs/base/browser/dom'; +import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; export interface IBaseActionViewItemOptions { draggable?: boolean; diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index 0dd80a02478..9f41732cd84 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./actionbar'; -import { Disposable, dispose } from 'vs/base/common/lifecycle'; -import { IAction, IActionRunner, ActionRunner, IRunEvent, Separator, IActionViewItem, IActionViewItemProvider } from 'vs/base/common/actions'; +import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { IAction, IActionRunner, ActionRunner, IRunEvent, Separator } from 'vs/base/common/actions'; import * as DOM from 'vs/base/browser/dom'; import * as types from 'vs/base/common/types'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; @@ -13,6 +13,19 @@ import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { Emitter } from 'vs/base/common/event'; import { IActionViewItemOptions, ActionViewItem, BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; +export interface IActionViewItem extends IDisposable { + actionRunner: IActionRunner; + setActionContext(context: any): void; + render(element: HTMLElement): void; + isEnabled(): boolean; + focus(fromRight?: boolean): void; // TODO@isidorn what is this? + blur(): void; +} + +export interface IActionViewItemProvider { + (action: IAction): IActionViewItem | undefined; +} + export const enum ActionsOrientation { HORIZONTAL, HORIZONTAL_REVERSE, diff --git a/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts b/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts index 5b46a52a549..67e2e9bb7c1 100644 --- a/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts +++ b/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./dropdown'; -import { Action, IAction, IActionRunner, IActionViewItemProvider } from 'vs/base/common/actions'; +import { Action, IAction, IActionRunner } from 'vs/base/common/actions'; import { IDisposable } from 'vs/base/common/lifecycle'; import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; import { ResolvedKeybinding } from 'vs/base/common/keyCodes'; @@ -14,6 +14,7 @@ import { ActionViewItem, BaseActionViewItem, IActionViewItemOptions, IBaseAction import { IActionProvider, DropdownMenu, IDropdownMenuOptions, ILabelRenderer } from 'vs/base/browser/ui/dropdown/dropdown'; import { IContextMenuProvider } from 'vs/base/browser/contextmenu'; import { Codicon } from 'vs/base/common/codicons'; +import { IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; export interface IKeybindingProvider { (action: IAction): ResolvedKeybinding | undefined; diff --git a/src/vs/base/browser/ui/menu/menu.ts b/src/vs/base/browser/ui/menu/menu.ts index 025428f4046..958d5f12868 100644 --- a/src/vs/base/browser/ui/menu/menu.ts +++ b/src/vs/base/browser/ui/menu/menu.ts @@ -5,8 +5,8 @@ import * as nls from 'vs/nls'; import * as strings from 'vs/base/common/strings'; -import { IActionRunner, IAction, SubmenuAction, Separator, IActionViewItemProvider, EmptySubmenuAction } from 'vs/base/common/actions'; -import { ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IActionRunner, IAction, SubmenuAction, Separator, EmptySubmenuAction } from 'vs/base/common/actions'; +import { ActionBar, ActionsOrientation, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; import { ResolvedKeybinding, KeyCode } from 'vs/base/common/keyCodes'; import { EventType, EventHelper, EventLike, isAncestor, addDisposableListener, append, $, clearNode, createStyleSheet, isInShadowDOM, getActiveElement, Dimension, IDomNodePagePosition } from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; diff --git a/src/vs/base/browser/ui/toolbar/toolbar.ts b/src/vs/base/browser/ui/toolbar/toolbar.ts index c1348a93ddc..8d1c5b6b17a 100644 --- a/src/vs/base/browser/ui/toolbar/toolbar.ts +++ b/src/vs/base/browser/ui/toolbar/toolbar.ts @@ -5,8 +5,8 @@ import 'vs/css!./toolbar'; import * as nls from 'vs/nls'; -import { Action, IActionRunner, IAction, IActionViewItemProvider, SubmenuAction } from 'vs/base/common/actions'; -import { ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; +import { Action, IActionRunner, IAction, SubmenuAction } from 'vs/base/common/actions'; +import { ActionBar, ActionsOrientation, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; import { ResolvedKeybinding } from 'vs/base/common/keyCodes'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; diff --git a/src/vs/base/common/actions.ts b/src/vs/base/common/actions.ts index 74db8a99f21..466be3c5cae 100644 --- a/src/vs/base/common/actions.ts +++ b/src/vs/base/common/actions.ts @@ -39,19 +39,6 @@ export interface IActionRunner extends IDisposable { readonly onBeforeRun: Event; } -export interface IActionViewItem extends IDisposable { - actionRunner: IActionRunner; - setActionContext(context: any): void; - render(element: any /* HTMLElement */): void; - isEnabled(): boolean; - focus(fromRight?: boolean): void; // TODO@isidorn what is this? - blur(): void; -} - -export interface IActionViewItemProvider { - (action: IAction): IActionViewItem | undefined; -} - export interface IActionChangeEvent { readonly label?: string; readonly tooltip?: string; diff --git a/src/vs/editor/contrib/suggest/suggestWidgetStatus.ts b/src/vs/editor/contrib/suggest/suggestWidgetStatus.ts index 3aa92bca3f4..5739f38f198 100644 --- a/src/vs/editor/contrib/suggest/suggestWidgetStatus.ts +++ b/src/vs/editor/contrib/suggest/suggestWidgetStatus.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import * as dom from 'vs/base/browser/dom'; -import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; -import { IActionViewItemProvider, IAction } from 'vs/base/common/actions'; +import { ActionBar, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IAction } from 'vs/base/common/actions'; import { ResolvedKeybinding } from 'vs/base/common/keyCodes'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { suggestWidgetStatusbarMenu } from 'vs/editor/contrib/suggest/suggest'; diff --git a/src/vs/workbench/browser/composite.ts b/src/vs/workbench/browser/composite.ts index c0087e858f9..ff991b74b94 100644 --- a/src/vs/workbench/browser/composite.ts +++ b/src/vs/workbench/browser/composite.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IAction, IActionRunner, ActionRunner, IActionViewItem } from 'vs/base/common/actions'; +import { IAction, IActionRunner, ActionRunner } from 'vs/base/common/actions'; import { Component } from 'vs/workbench/common/component'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IComposite, ICompositeControl } from 'vs/workbench/common/composite'; @@ -14,6 +14,7 @@ import { trackFocus, Dimension } from 'vs/base/browser/dom'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { Disposable } from 'vs/base/common/lifecycle'; import { assertIsDefined } from 'vs/base/common/types'; +import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; /** * Composites are layed out in the sidebar and panel part of the workbench. At a time only one composite diff --git a/src/vs/workbench/browser/panecomposite.ts b/src/vs/workbench/browser/panecomposite.ts index 9113801e2a0..38e33e2bee8 100644 --- a/src/vs/workbench/browser/panecomposite.ts +++ b/src/vs/workbench/browser/panecomposite.ts @@ -15,8 +15,9 @@ import { Composite } from 'vs/workbench/browser/composite'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { ViewPaneContainer, ViewsSubMenu } from './parts/views/viewPaneContainer'; import { IPaneComposite } from 'vs/workbench/common/panecomposite'; -import { IAction, IActionViewItem, Separator } from 'vs/base/common/actions'; +import { IAction, Separator } from 'vs/base/common/actions'; import { SubmenuItemAction } from 'vs/platform/actions/common/actions'; +import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; export abstract class PaneComposite extends Composite implements IPaneComposite { diff --git a/src/vs/workbench/browser/parts/compositePart.ts b/src/vs/workbench/browser/parts/compositePart.ts index 5f9b29f4587..1ead62e5b8e 100644 --- a/src/vs/workbench/browser/parts/compositePart.ts +++ b/src/vs/workbench/browser/parts/compositePart.ts @@ -10,9 +10,9 @@ import { IDisposable, dispose, DisposableStore, MutableDisposable } from 'vs/bas import { Emitter } from 'vs/base/common/event'; import { isPromiseCanceledError } from 'vs/base/common/errors'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; -import { ActionsOrientation, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionsOrientation, IActionViewItem, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar'; import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; -import { IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification, IActionViewItem } from 'vs/base/common/actions'; +import { IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; import { Part, IPartOptions } from 'vs/workbench/browser/part'; import { Composite, CompositeRegistry } from 'vs/workbench/browser/composite'; import { IComposite } from 'vs/workbench/common/composite'; diff --git a/src/vs/workbench/browser/parts/editor/titleControl.ts b/src/vs/workbench/browser/parts/editor/titleControl.ts index f45f9ed0a6f..8677017e740 100644 --- a/src/vs/workbench/browser/parts/editor/titleControl.ts +++ b/src/vs/workbench/browser/parts/editor/titleControl.ts @@ -7,9 +7,9 @@ import 'vs/css!./media/titlecontrol'; import { applyDragImage, DataTransfers } from 'vs/base/browser/dnd'; import { addDisposableListener, Dimension, EventType } from 'vs/base/browser/dom'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; -import { ActionsOrientation, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionsOrientation, IActionViewItem, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; -import { IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification, IActionViewItem, SubmenuAction } from 'vs/base/common/actions'; +import { IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification, SubmenuAction } from 'vs/base/common/actions'; import { ResolvedKeybinding } from 'vs/base/common/keyCodes'; import { dispose, DisposableStore } from 'vs/base/common/lifecycle'; import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; diff --git a/src/vs/workbench/browser/parts/views/treeView.ts b/src/vs/workbench/browser/parts/views/treeView.ts index 9c49ffdcca2..04482e7d7f1 100644 --- a/src/vs/workbench/browser/parts/views/treeView.ts +++ b/src/vs/workbench/browser/parts/views/treeView.ts @@ -19,7 +19,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { Event, Emitter } from 'vs/base/common/event'; -import { IAction, ActionRunner, IActionViewItemProvider } from 'vs/base/common/actions'; +import { IAction, ActionRunner } from 'vs/base/common/actions'; import { createAndFillInContextMenuActions, createActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IProgressService } from 'vs/platform/progress/common/progress'; @@ -27,7 +27,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten import { ICommandService } from 'vs/platform/commands/common/commands'; import * as DOM from 'vs/base/browser/dom'; import { ResourceLabels, IResourceLabel } from 'vs/workbench/browser/labels'; -import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionBar, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; import { URI } from 'vs/base/common/uri'; import { dirname, basename } from 'vs/base/common/resources'; import { FileKind } from 'vs/platform/files/common/files'; diff --git a/src/vs/workbench/browser/parts/views/viewPane.ts b/src/vs/workbench/browser/parts/views/viewPane.ts index b4090a285c7..835620f11a9 100644 --- a/src/vs/workbench/browser/parts/views/viewPane.ts +++ b/src/vs/workbench/browser/parts/views/viewPane.ts @@ -11,8 +11,8 @@ import { attachButtonStyler, attachLinkStyler, attachProgressBarStyler } from 'v import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; import { after, append, $, trackFocus, EventType, addDisposableListener, createCSSRule, asCSSUrl } from 'vs/base/browser/dom'; import { IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { IAction, IActionViewItem } from 'vs/base/common/actions'; -import { ActionsOrientation, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IAction } from 'vs/base/common/actions'; +import { ActionsOrientation, IActionViewItem, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar'; import { Registry } from 'vs/platform/registry/common/platform'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; diff --git a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts index 21d60451af4..32db51de439 100644 --- a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts +++ b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts @@ -11,7 +11,7 @@ import { attachStyler, IColorMapping } 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_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 { EventType, Dimension, addDisposableListener, isAncestor } from 'vs/base/browser/dom'; import { IDisposable, combinedDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; -import { IAction, IActionViewItem } from 'vs/base/common/actions'; +import { IAction } from 'vs/base/common/actions'; 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'; @@ -37,6 +37,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis import { ViewPane } from 'vs/workbench/browser/parts/views/viewPane'; import { CompositeMenuActions } from 'vs/workbench/browser/menuActions'; import { createActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; export const ViewsSubMenu = new MenuId('Views'); MenuRegistry.appendMenuItem(MenuId.ViewContainerTitle, { diff --git a/src/vs/workbench/contrib/debug/browser/debugViewlet.ts b/src/vs/workbench/contrib/debug/browser/debugViewlet.ts index 5139f3384dd..d1c14273d55 100644 --- a/src/vs/workbench/contrib/debug/browser/debugViewlet.ts +++ b/src/vs/workbench/contrib/debug/browser/debugViewlet.ts @@ -5,7 +5,7 @@ import 'vs/css!./media/debugViewlet'; import * as nls from 'vs/nls'; -import { IAction, IActionViewItem } from 'vs/base/common/actions'; +import { IAction } from 'vs/base/common/actions'; import { IDebugService, VIEWLET_ID, State, BREAKPOINTS_VIEW_ID, CONTEXT_DEBUG_UX, CONTEXT_DEBUG_UX_KEY, REPL_VIEW_ID, CONTEXT_DEBUG_STATE, ILaunch, getStateLabel, CONTEXT_DEBUGGERS_AVAILABLE } from 'vs/workbench/contrib/debug/common/debug'; import { StartDebugActionViewItem, FocusSessionActionViewItem } from 'vs/workbench/contrib/debug/browser/debugActionViewItems'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; @@ -30,6 +30,7 @@ import { debugConfigure } from 'vs/workbench/contrib/debug/browser/debugIcons'; import { WorkbenchStateContext } from 'vs/workbench/browser/contextkeys'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { FOCUS_SESSION_ID, SELECT_AND_START_ID, DEBUG_CONFIGURE_COMMAND_ID, DEBUG_CONFIGURE_LABEL, DEBUG_START_LABEL, DEBUG_START_COMMAND_ID } from 'vs/workbench/contrib/debug/browser/debugCommands'; +import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; export class DebugViewPaneContainer extends ViewPaneContainer { diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index 46cd8f54f9d..b8f12426720 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -5,7 +5,7 @@ import 'vs/css!./media/repl'; import { URI as uri } from 'vs/base/common/uri'; -import { IAction, IActionViewItem } from 'vs/base/common/actions'; +import { IAction } from 'vs/base/common/actions'; import * as dom from 'vs/base/browser/dom'; import * as aria from 'vs/base/browser/ui/aria/aria'; import { CancellationToken } from 'vs/base/common/cancellation'; @@ -62,6 +62,7 @@ import { ReplFilter, ReplFilterState, ReplFilterActionViewItem } from 'vs/workbe import { debugConsoleClearAll, debugConsoleEvaluationPrompt } from 'vs/workbench/contrib/debug/browser/debugIcons'; import { registerAction2, MenuId, Action2, IMenuService, IMenu } from 'vs/platform/actions/common/actions'; import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; const $ = dom.$; diff --git a/src/vs/workbench/contrib/markers/browser/markersView.ts b/src/vs/workbench/contrib/markers/browser/markersView.ts index b2a7ce0f6f5..5f8de976926 100644 --- a/src/vs/workbench/contrib/markers/browser/markersView.ts +++ b/src/vs/workbench/contrib/markers/browser/markersView.ts @@ -7,7 +7,7 @@ import 'vs/css!./media/markers'; import { URI } from 'vs/base/common/uri'; import * as dom from 'vs/base/browser/dom'; -import { IAction, IActionViewItem, Action, Separator } from 'vs/base/common/actions'; +import { IAction, Action, Separator } from 'vs/base/common/actions'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import Constants from 'vs/workbench/contrib/markers/browser/constants'; @@ -32,7 +32,7 @@ import { deepClone } from 'vs/base/common/objects'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { FilterData, Filter, VirtualDelegate, ResourceMarkersRenderer, MarkerRenderer, RelatedInformationRenderer, MarkersTreeAccessibilityProvider, MarkersViewModel, ResourceDragAndDrop } from 'vs/workbench/contrib/markers/browser/markersTreeViewer'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionBar, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IMenuService, MenuId } from 'vs/platform/actions/common/actions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; diff --git a/src/vs/workbench/contrib/output/browser/outputView.ts b/src/vs/workbench/contrib/output/browser/outputView.ts index ddd71be77d1..d7c7c6ddb69 100644 --- a/src/vs/workbench/contrib/output/browser/outputView.ts +++ b/src/vs/workbench/contrib/output/browser/outputView.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import { IAction, IActionViewItem } from 'vs/base/common/actions'; +import { IAction } from 'vs/base/common/actions'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -36,6 +36,7 @@ import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; import { editorBackground, selectBorder } from 'vs/platform/theme/common/colorRegistry'; import { SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; import { Dimension } from 'vs/base/browser/dom'; +import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; export class OutputViewPane extends ViewPane { diff --git a/src/vs/workbench/contrib/remote/browser/remote.ts b/src/vs/workbench/contrib/remote/browser/remote.ts index bb18656a314..bbb6695f3c2 100644 --- a/src/vs/workbench/contrib/remote/browser/remote.ts +++ b/src/vs/workbench/contrib/remote/browser/remote.ts @@ -36,7 +36,7 @@ import { ReloadWindowAction } from 'vs/workbench/browser/actions/windowActions'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { SwitchRemoteViewItem, SwitchRemoteAction } from 'vs/workbench/contrib/remote/browser/explorerViewItems'; -import { Action, IActionViewItem } from 'vs/base/common/actions'; +import { Action } from 'vs/base/common/actions'; import { isStringArray } from 'vs/base/common/types'; import { IRemoteExplorerService } from 'vs/workbench/services/remote/common/remoteExplorerService'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -53,6 +53,7 @@ import * as icons from 'vs/workbench/contrib/remote/browser/remoteIcons'; import { ILogService } from 'vs/platform/log/common/log'; import { ITimerService } from 'vs/workbench/services/timer/browser/timerService'; import { getRemoteName } from 'vs/platform/remote/common/remoteHosts'; +import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; export interface HelpInformation { diff --git a/src/vs/workbench/contrib/scm/browser/scmRepositoryRenderer.ts b/src/vs/workbench/contrib/scm/browser/scmRepositoryRenderer.ts index ffcb36be97f..739853ebdb7 100644 --- a/src/vs/workbench/contrib/scm/browser/scmRepositoryRenderer.ts +++ b/src/vs/workbench/contrib/scm/browser/scmRepositoryRenderer.ts @@ -10,7 +10,7 @@ import { ISCMRepository, ISCMViewService } from 'vs/workbench/contrib/scm/common import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IAction, IActionViewItemProvider } from 'vs/base/common/actions'; +import { IAction } from 'vs/base/common/actions'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { connectPrimaryMenu, isSCMRepository, StatusBarAction } from './util'; import { attachBadgeStyler } from 'vs/platform/theme/common/styler'; @@ -21,6 +21,7 @@ import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; import { IListRenderer } from 'vs/base/browser/ui/list/list'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { basename } from 'vs/base/common/resources'; +import { IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; interface RepositoryTemplate { readonly label: HTMLElement; diff --git a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts index 9e49aa3061c..f0bb38ed9f7 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts @@ -20,8 +20,8 @@ import { IContextKeyService, IContextKey, ContextKeyExpr, RawContextKey } from ' import { ICommandService } from 'vs/platform/commands/common/commands'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { MenuItemAction, IMenuService, registerAction2, MenuId, IAction2Options, MenuRegistry, Action2 } from 'vs/platform/actions/common/actions'; -import { IAction, ActionRunner, IActionViewItemProvider } from 'vs/base/common/actions'; -import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IAction, ActionRunner } from 'vs/base/common/actions'; +import { ActionBar, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; import { IThemeService, registerThemingParticipant, IFileIconTheme } from 'vs/platform/theme/common/themeService'; import { isSCMResource, isSCMResourceGroup, connectPrimaryMenuToInlineActionBar, isSCMRepository, isSCMInput, collectContextMenuActions, getActionViewItemProvider } from './util'; import { attachBadgeStyler } from 'vs/platform/theme/common/styler'; diff --git a/src/vs/workbench/contrib/scm/browser/util.ts b/src/vs/workbench/contrib/scm/browser/util.ts index 7d916c437d5..007d674bac3 100644 --- a/src/vs/workbench/contrib/scm/browser/util.ts +++ b/src/vs/workbench/contrib/scm/browser/util.ts @@ -5,9 +5,9 @@ import { ISCMResource, ISCMRepository, ISCMResourceGroup, ISCMInput } from 'vs/workbench/contrib/scm/common/scm'; import { IMenu } from 'vs/platform/actions/common/actions'; -import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionBar, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; import { IDisposable, Disposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle'; -import { Action, IAction, IActionViewItemProvider } from 'vs/base/common/actions'; +import { Action, IAction } from 'vs/base/common/actions'; import { createActionViewItem, createAndFillInActionBarActions, createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { equals } from 'vs/base/common/arrays'; import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalView.ts b/src/vs/workbench/contrib/terminal/browser/terminalView.ts index fa6cbfcab7d..c24ce885c6b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalView.ts @@ -6,7 +6,7 @@ import * as dom from 'vs/base/browser/dom'; import * as nls from 'vs/nls'; import * as platform from 'vs/base/common/platform'; -import { Action, IAction, IActionViewItem } from 'vs/base/common/actions'; +import { Action, IAction } from 'vs/base/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -36,6 +36,7 @@ import { selectBorder } from 'vs/platform/theme/common/colorRegistry'; import { ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox'; import { equals } from 'vs/base/common/arrays'; import { BrowserFeatures } from 'vs/base/browser/canIUse'; +import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; const FIND_FOCUS_CLASS = 'find-focused'; diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts index 914cb37bec2..51c0af3a7d5 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts @@ -5,7 +5,7 @@ import * as dom from 'vs/base/browser/dom'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionBar, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; import * as aria from 'vs/base/browser/ui/aria/aria'; import { Button } from 'vs/base/browser/ui/button/button'; import { IIdentityProvider, IKeyboardNavigationLabelProvider, IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; @@ -13,7 +13,7 @@ import { DefaultKeyboardNavigationDelegate, IListAccessibilityProvider } from 'v import { ICompressedTreeNode } from 'vs/base/browser/ui/tree/compressedObjectTreeModel'; import { ObjectTree } from 'vs/base/browser/ui/tree/objectTree'; import { ITreeEvent, ITreeFilter, ITreeNode, ITreeRenderer, ITreeSorter, TreeFilterResult, TreeVisibility } from 'vs/base/browser/ui/tree/tree'; -import { Action, IAction, IActionViewItem } from 'vs/base/common/actions'; +import { Action, IAction } from 'vs/base/common/actions'; import { DeferredPromise, RunOnceScheduler } from 'vs/base/common/async'; import { Color, RGBA } from 'vs/base/common/color'; import { throttle } from 'vs/base/common/decorators'; diff --git a/src/vs/workbench/contrib/timeline/browser/timelinePane.ts b/src/vs/workbench/contrib/timeline/browser/timelinePane.ts index f3277edc2fa..a0b5aa73388 100644 --- a/src/vs/workbench/contrib/timeline/browser/timelinePane.ts +++ b/src/vs/workbench/contrib/timeline/browser/timelinePane.ts @@ -6,7 +6,7 @@ import 'vs/css!./media/timelinePane'; import { localize } from 'vs/nls'; import * as DOM from 'vs/base/browser/dom'; -import { IAction, ActionRunner, IActionViewItemProvider } from 'vs/base/common/actions'; +import { IAction, ActionRunner } from 'vs/base/common/actions'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { fromNow } from 'vs/base/common/date'; import { debounce } from 'vs/base/common/decorators'; @@ -36,7 +36,7 @@ import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService' import { IViewDescriptorService } from 'vs/workbench/common/views'; import { IProgressService } from 'vs/platform/progress/common/progress'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionBar, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; import { createAndFillInContextMenuActions, createActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IMenuService, MenuId, registerAction2, Action2, MenuRegistry } from 'vs/platform/actions/common/actions'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; From eb50a52badcd4ec9857b053093f39170f1c15081 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 18 Feb 2021 09:32:40 +0100 Subject: [PATCH 302/325] update distro --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index b78d2019ffb..4e0eaa0036f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.54.0", - "distro": "79c9c6cd047952944225cf04f5b19094d162e77f", + "distro": "918cb1526e6442d55ef2c4e617f77afe48f6a3fe", "author": { "name": "Microsoft Corporation" }, @@ -222,4 +222,4 @@ "elliptic": "^6.5.3", "nwmatcher": "^1.4.4" } -} +} \ No newline at end of file From 16510dfc86c47acb8a9b9b0a051dfba9e0a5de57 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 18 Feb 2021 04:29:19 -0800 Subject: [PATCH 303/325] Remove logs from test --- .../src/singlefolder-tests/terminal.test.ts | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index c28ece13fd1..5e7a544291d 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -56,55 +56,38 @@ import { assertNoRpc } from '../utils'; }); test('echo works in the default shell', async () => { - console.log(' test 1'); const terminal = await new Promise(r => { - console.log(' test 2'); disposables.push(window.onDidOpenTerminal(t => { - console.log(' test 3'); strictEqual(terminal, t); r(terminal); })); - console.log(' test 4'); // Use a single character to avoid winpty/conpty issues with injected sequences const terminal = window.createTerminal({ env: { TEST: '`' } }); - console.log(' test 5'); terminal.show(); }); - console.log(' test 6'); let data = ''; await new Promise(r => { - console.log(' test 7'); disposables.push(window.onDidWriteTerminalData(e => { - console.log(' test 8.1'); strictEqual(terminal, e.terminal); - console.log(' test 8.2'); data += e.data; - console.log(' test 8.3, data=' + data); if (data.indexOf('`') !== 0) { - console.log(' test 9'); r(); } })); // Print an environment variable value so the echo statement doesn't get matched if (process.platform === 'win32') { - console.log(' test 10'); terminal.sendText(`$env:TEST`); } else { - console.log(' test 11'); terminal.sendText(`echo $TEST`); } }); - console.log(' test 12'); await new Promise(r => { - console.log(' test 1'); terminal.dispose(); - console.log(' test 14'); disposables.push(window.onDidCloseTerminal(t => { - console.log(' test 15'); strictEqual(terminal, t); r(); })); From a6cc65462a28e06ff2e2a1ec3c4aedccdae2fc03 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 18 Feb 2021 04:29:59 -0800 Subject: [PATCH 304/325] Re-enable pty host restarting --- .../electron-browser/localPtyService.ts | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/vs/platform/terminal/electron-browser/localPtyService.ts b/src/vs/platform/terminal/electron-browser/localPtyService.ts index e39be645dc7..dfc72dc3b44 100644 --- a/src/vs/platform/terminal/electron-browser/localPtyService.ts +++ b/src/vs/platform/terminal/electron-browser/localPtyService.ts @@ -13,9 +13,9 @@ import { IProcessEnvironment } from 'vs/base/common/platform'; import { Emitter } from 'vs/base/common/event'; import { LogLevelChannelClient } from 'vs/platform/log/common/logIpc'; -// enum Constants { -// MaxRestarts = 5 -// } +enum Constants { + MaxRestarts = 5 +} export class LocalPtyService extends Disposable implements IPtyService { declare readonly _serviceBrand: undefined; @@ -23,8 +23,8 @@ export class LocalPtyService extends Disposable implements IPtyService { // ProxyChannel is not used here because events get lost when forwarding across multiple proxies private _proxy: IPtyService; - // private _restartCount = 0; - // private _isDisposed = false; + private _restartCount = 0; + private _isDisposed = false; private readonly _onPtyHostExit = this._register(new Emitter()); readonly onPtyHostExit = this._onPtyHostExit.event; @@ -78,15 +78,15 @@ export class LocalPtyService extends Disposable implements IPtyService { }); this._register(client.onDidProcessExit(e => { this._onPtyHostExit.fire(e.code); - // if (!this._isDisposed) { - // if (this._restartCount <= Constants.MaxRestarts) { - // this._logService.error(`ptyHost terminated unexpectedly with code ${e.code}`); - // this._restartCount++; - // this._proxy = this._startPtyHost(); - // } else { - // this._logService.error(`ptyHost terminated unexpectedly with code ${e.code}, giving up`); - // } - // } + if (!this._isDisposed) { + if (this._restartCount <= Constants.MaxRestarts) { + this._logService.error(`ptyHost terminated unexpectedly with code ${e.code}`); + this._restartCount++; + this._proxy = this._startPtyHost(); + } else { + this._logService.error(`ptyHost terminated unexpectedly with code ${e.code}, giving up`); + } + } })); // Setup logging @@ -107,7 +107,7 @@ export class LocalPtyService extends Disposable implements IPtyService { } dispose() { - // this._isDisposed = true; + this._isDisposed = true; super.dispose(); } From da0086512c27e41bfc844aa9300749ef7498ac12 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 18 Feb 2021 05:34:56 -0800 Subject: [PATCH 305/325] Update distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 309c981f28d..cac97e94e70 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.54.0", - "distro": "a72de2db04cc4899a14bf228401b10e48f861abe", + "distro": "bb7724655cd33d9e9fa31c98ca48a306147c276a", "author": { "name": "Microsoft Corporation" }, From e10085761b1ddc449b84db2690075f11cf1a3e4b Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 18 Feb 2021 05:41:19 -0800 Subject: [PATCH 306/325] Update distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cac97e94e70..59bf1158a51 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.54.0", - "distro": "bb7724655cd33d9e9fa31c98ca48a306147c276a", + "distro": "8abc3b69c9a71c8da5a17f3e06068485a0a90c4c", "author": { "name": "Microsoft Corporation" }, From c714b56e80488bac7ae0f49c1576e82aa4b9bcbd Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 18 Feb 2021 06:26:14 -0800 Subject: [PATCH 307/325] Simplify events in LocalPty --- .../contrib/terminal/electron-sandbox/localPty.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts index 87f780b71e1..09bbb9a43fc 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Emitter, Event } from 'vs/base/common/event'; +import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { IShellLaunchConfig, ITerminalLaunchError, ITerminalChildProcess, ITerminalDimensionsOverride, IProcessDataEvent } from 'vs/platform/terminal/common/terminal'; import { ILocalPtyService } from 'vs/platform/terminal/electron-sandbox/terminal'; @@ -14,17 +14,17 @@ import { ILocalPtyService } from 'vs/platform/terminal/electron-sandbox/terminal */ export class LocalPty extends Disposable implements ITerminalChildProcess { private readonly _onProcessData = this._register(new Emitter()); - public readonly onProcessData: Event = this._onProcessData.event; + public readonly onProcessData = this._onProcessData.event; private readonly _onProcessExit = this._register(new Emitter()); - public readonly onProcessExit: Event = this._onProcessExit.event; + public readonly onProcessExit = this._onProcessExit.event; private readonly _onProcessReady = this._register(new Emitter<{ pid: number, cwd: string }>()); - public get onProcessReady(): Event<{ pid: number, cwd: string }> { return this._onProcessReady.event; } + public readonly onProcessReady = this._onProcessReady.event; private readonly _onProcessTitleChanged = this._register(new Emitter()); - public readonly onProcessTitleChanged: Event = this._onProcessTitleChanged.event; + public readonly onProcessTitleChanged = this._onProcessTitleChanged.event; private readonly _onProcessOverrideDimensions = this._register(new Emitter()); - public get onProcessOverrideDimensions(): Event { return this._onProcessOverrideDimensions.event; } + public readonly onProcessOverrideDimensions = this._onProcessOverrideDimensions.event; private readonly _onProcessResolvedShellLaunchConfig = this._register(new Emitter()); - public get onProcessResolvedShellLaunchConfig(): Event { return this._onProcessResolvedShellLaunchConfig.event; } + public readonly onProcessResolvedShellLaunchConfig = this._onProcessResolvedShellLaunchConfig.event; constructor( private readonly _localPtyId: number, From e8928ea67892880203d7064591dd628b2bf34e9b Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 18 Feb 2021 15:29:23 +0100 Subject: [PATCH 308/325] use product name --- src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 1d9a753a1bb..2524044c559 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -347,7 +347,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo else { this.notificationService.notify({ severity: Severity.Info, - message: localize('service changed and turned off', "Settings sync was turned off because VSCode now uses a separate service. Please turn on sync again."), + message: localize('service changed and turned off', "Settings sync was turned off because {0} now uses a separate service. Please turn on sync again.", this.productService.nameLong), actions: { primary: [new Action('turn on sync', localize('turn on sync', "Turn on Settings Sync..."), undefined, true, () => this.turnOn())] } From 692f1465a82d96b965530fb0c4b1d2cfb9b8f931 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 18 Feb 2021 16:01:06 +0100 Subject: [PATCH 309/325] Fix #116691 --- src/vs/platform/log/browser/log.ts | 14 +- src/vs/platform/log/common/log.ts | 14 +- src/vs/platform/log/common/logIpc.ts | 180 +++++++++++------- .../electron-browser/desktop.main.ts | 4 +- .../electron-sandbox/desktop.main.ts | 4 +- .../log/electron-sandbox/logService.ts | 5 +- .../log/electron-sandbox/loggerService.ts | 61 ------ 7 files changed, 139 insertions(+), 143 deletions(-) delete mode 100644 src/vs/workbench/services/log/electron-sandbox/loggerService.ts diff --git a/src/vs/platform/log/browser/log.ts b/src/vs/platform/log/browser/log.ts index 8b1d44c4b91..8fe0f14599d 100644 --- a/src/vs/platform/log/browser/log.ts +++ b/src/vs/platform/log/browser/log.ts @@ -9,6 +9,18 @@ interface IAutomatedWindow { codeAutomationLog(type: string, args: any[]): void; } +function logLevelToString(level: LogLevel): string { + switch (level) { + case LogLevel.Trace: return 'trace'; + case LogLevel.Debug: return 'debug'; + case LogLevel.Info: return 'info'; + case LogLevel.Warning: return 'warn'; + case LogLevel.Error: return 'error'; + case LogLevel.Critical: return 'critical'; + } + return 'info'; +} + /** * A logger that is used when VSCode is running in the web with * an automation such as playwright. We expect a global codeAutomationLog @@ -19,7 +31,7 @@ export class ConsoleLogInAutomationLogger extends AdapterLogger implements ILogg declare codeAutomationLog: any; constructor(logLevel: LogLevel = DEFAULT_LOG_LEVEL) { - super({ log: (type, args) => this.consoleLog(type, args) }, logLevel); + super({ log: (level, args) => this.consoleLog(logLevelToString(level), args) }, logLevel); } private consoleLog(type: string, args: any[]): void { diff --git a/src/vs/platform/log/common/log.ts b/src/vs/platform/log/common/log.ts index 524381951d1..8a2764bc6c4 100644 --- a/src/vs/platform/log/common/log.ts +++ b/src/vs/platform/log/common/log.ts @@ -314,44 +314,44 @@ export class ConsoleLogger extends AbstractLogger implements ILogger { export class AdapterLogger extends AbstractLogger implements ILogger { - constructor(private readonly adapter: { log: (type: string, args: any[]) => void }, logLevel: LogLevel = DEFAULT_LOG_LEVEL) { + constructor(private readonly adapter: { log: (logLevel: LogLevel, args: any[]) => void }, logLevel: LogLevel = DEFAULT_LOG_LEVEL) { super(); this.setLevel(logLevel); } trace(message: string, ...args: any[]): void { if (this.getLevel() <= LogLevel.Trace) { - this.adapter.log('trace', [this.extractMessage(message), ...args]); + this.adapter.log(LogLevel.Trace, [this.extractMessage(message), ...args]); } } debug(message: string, ...args: any[]): void { if (this.getLevel() <= LogLevel.Debug) { - this.adapter.log('debug', [this.extractMessage(message), ...args]); + this.adapter.log(LogLevel.Debug, [this.extractMessage(message), ...args]); } } info(message: string, ...args: any[]): void { if (this.getLevel() <= LogLevel.Info) { - this.adapter.log('info', [this.extractMessage(message), ...args]); + this.adapter.log(LogLevel.Info, [this.extractMessage(message), ...args]); } } warn(message: string | Error, ...args: any[]): void { if (this.getLevel() <= LogLevel.Warning) { - this.adapter.log('warn', [this.extractMessage(message), ...args]); + this.adapter.log(LogLevel.Warning, [this.extractMessage(message), ...args]); } } error(message: string | Error, ...args: any[]): void { if (this.getLevel() <= LogLevel.Error) { - this.adapter.log('error', [this.extractMessage(message), ...args]); + this.adapter.log(LogLevel.Error, [this.extractMessage(message), ...args]); } } critical(message: string | Error, ...args: any[]): void { if (this.getLevel() <= LogLevel.Critical) { - this.adapter.log('critical', [this.extractMessage(message), ...args]); + this.adapter.log(LogLevel.Critical, [this.extractMessage(message), ...args]); } } diff --git a/src/vs/platform/log/common/logIpc.ts b/src/vs/platform/log/common/logIpc.ts index 4c18165d9b4..4b8ac5fab13 100644 --- a/src/vs/platform/log/common/logIpc.ts +++ b/src/vs/platform/log/common/logIpc.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { LogLevel, ILogService, LogService, ILoggerService, ILogger, AbstractMessageLogger, ILoggerOptions } from 'vs/platform/log/common/log'; +import { LogLevel, ILogService, LogService, ILoggerService, ILogger, AbstractMessageLogger, ILoggerOptions, AdapterLogger } from 'vs/platform/log/common/log'; import { Event } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; @@ -34,72 +34,6 @@ export class LogLevelChannel implements IServerChannel { } -export class LoggerChannel implements IServerChannel { - - private consoleLogger: ILogger | undefined; - private readonly loggers = new Map(); - - constructor(private readonly loggerService: ILoggerService) { } - - listen(_: unknown, event: string): Event { - throw new Error(`Event not found: ${event}`); - } - - async call(_: unknown, command: string, arg?: any): Promise { - switch (command) { - case 'createConsoleLogger': return this.createConsoleLogger(); - case 'createLogger': this.createLogger(URI.revive(arg[0]), arg[1]); return; - case 'log': return this.log(URI.revive(arg[0]), arg[1]); - } - - throw new Error(`Call not found: ${command}`); - } - - private createConsoleLogger(): void { - this.consoleLogger = new class extends AbstractMessageLogger { - protected log(level: LogLevel, message: string) { - let consoleFn = console.log; - - switch (level) { - case LogLevel.Error: - consoleFn = console.error; - break; - case LogLevel.Warning: - consoleFn = console.warn; - break; - case LogLevel.Info: - consoleFn = console.info; - break; - } - - consoleFn.call(console, message); - } - }(); - } - - private createLogger(file: URI, options: ILoggerOptions): void { - this.loggers.set(file.toString(), this.loggerService.createLogger(file, options)); - } - - private log(file: URI | undefined, messages: [LogLevel, string][]): void { - const logger = file ? this.loggers.get(file.toString()) : this.consoleLogger; - if (!logger) { - throw new Error('Create the logger before logging'); - } - for (const [level, message] of messages) { - switch (level) { - case LogLevel.Trace: logger.trace(message); break; - case LogLevel.Debug: logger.debug(message); break; - case LogLevel.Info: logger.info(message); break; - case LogLevel.Warning: logger.warn(message); break; - case LogLevel.Error: logger.error(message); break; - case LogLevel.Critical: logger.critical(message); break; - default: throw new Error('Invalid log level'); - } - } - } -} - export class LogLevelChannelClient { constructor(private channel: IChannel) { } @@ -118,6 +52,118 @@ export class LogLevelChannelClient { } +export class LoggerChannel implements IServerChannel { + + private readonly loggers = new Map(); + + constructor(private readonly loggerService: ILoggerService) { } + + listen(_: unknown, event: string): Event { + throw new Error(`Event not found: ${event}`); + } + + async call(_: unknown, command: string, arg?: any): Promise { + switch (command) { + case 'createLogger': this.createLogger(URI.revive(arg[0]), arg[1]); return; + case 'log': return this.log(URI.revive(arg[0]), arg[1]); + case 'consoleLog': return this.consoleLog(arg[0], arg[1]); + } + + throw new Error(`Call not found: ${command}`); + } + + private createLogger(file: URI, options: ILoggerOptions): void { + this.loggers.set(file.toString(), this.loggerService.createLogger(file, options)); + } + + private consoleLog(level: LogLevel, args: any[]): void { + let consoleFn = console.log; + + switch (level) { + case LogLevel.Error: + consoleFn = console.error; + break; + case LogLevel.Warning: + consoleFn = console.warn; + break; + case LogLevel.Info: + consoleFn = console.info; + break; + } + + consoleFn.call(console, ...args); + } + + private log(file: URI, messages: [LogLevel, string][]): void { + const logger = this.loggers.get(file.toString()); + if (!logger) { + throw new Error('Create the logger before logging'); + } + for (const [level, message] of messages) { + switch (level) { + case LogLevel.Trace: logger.trace(message); break; + case LogLevel.Debug: logger.debug(message); break; + case LogLevel.Info: logger.info(message); break; + case LogLevel.Warning: logger.warn(message); break; + case LogLevel.Error: logger.error(message); break; + case LogLevel.Critical: logger.critical(message); break; + default: throw new Error('Invalid log level'); + } + } + } +} + +export class LoggerChannelClient implements ILoggerService { + + declare readonly _serviceBrand: undefined; + + constructor(private readonly channel: IChannel) { } + + createConsoleMainLogger(): ILogger { + return new AdapterLogger({ + log: (level: LogLevel, args: any[]) => { + this.channel.call('consoleLog', [level, args]); + } + }); + } + + createLogger(file: URI, options?: ILoggerOptions): ILogger { + return new Logger(this.channel, file, options); + } + +} + +class Logger extends AbstractMessageLogger { + + private isLoggerCreated: boolean = false; + private buffer: [LogLevel, string][] = []; + + constructor( + private readonly channel: IChannel, + private readonly file: URI, + loggerOptions?: ILoggerOptions, + ) { + super(loggerOptions?.always); + this.channel.call('createLogger', [file, loggerOptions]) + .then(() => { + this._log(this.buffer); + this.isLoggerCreated = true; + }); + } + + protected log(level: LogLevel, message: string) { + this._log([[level, message]]); + } + + private _log(messages: [LogLevel, string][]) { + if (this.isLoggerCreated) { + this.channel.call('log', [this.file, messages]); + } else { + this.buffer.push(...messages); + } + } +} + export class FollowerLogService extends LogService implements ILogService { declare readonly _serviceBrand: undefined; diff --git a/src/vs/workbench/electron-browser/desktop.main.ts b/src/vs/workbench/electron-browser/desktop.main.ts index bcd53444318..8ffa5670f52 100644 --- a/src/vs/workbench/electron-browser/desktop.main.ts +++ b/src/vs/workbench/electron-browser/desktop.main.ts @@ -52,8 +52,8 @@ import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/ur import { UriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentityService'; import { KeyboardLayoutService } from 'vs/workbench/services/keybinding/electron-sandbox/nativeKeyboardLayout'; import { IKeyboardLayoutService } from 'vs/platform/keyboardLayout/common/keyboardLayout'; -import { LoggerService } from 'vs/workbench/services/log/electron-sandbox/loggerService'; import { ElectronIPCMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService'; +import { LoggerChannelClient } from 'vs/platform/log/common/logIpc'; class DesktopMain extends Disposable { @@ -170,7 +170,7 @@ class DesktopMain extends Disposable { serviceCollection.set(IProductService, this.productService); // Logger - const loggerService = new LoggerService(mainProcessService); + const loggerService = new LoggerChannelClient(mainProcessService.getChannel('logger')); serviceCollection.set(ILoggerService, loggerService); // Log diff --git a/src/vs/workbench/electron-sandbox/desktop.main.ts b/src/vs/workbench/electron-sandbox/desktop.main.ts index 709c3ab30c1..d470723f747 100644 --- a/src/vs/workbench/electron-sandbox/desktop.main.ts +++ b/src/vs/workbench/electron-sandbox/desktop.main.ts @@ -42,9 +42,9 @@ import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/ur import { UriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentityService'; import { KeyboardLayoutService } from 'vs/workbench/services/keybinding/electron-sandbox/nativeKeyboardLayout'; import { IKeyboardLayoutService } from 'vs/platform/keyboardLayout/common/keyboardLayout'; -import { LoggerService } from 'vs/workbench/services/log/electron-sandbox/loggerService'; import { ElectronIPCMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService'; import { SimpleConfigurationService, simpleFileSystemProvider, SimpleSignService, SimpleNativeWorkbenchEnvironmentService, SimpleWorkspaceService } from 'vs/workbench/electron-sandbox/sandbox.simpleservices'; +import { LoggerChannelClient } from 'vs/platform/log/common/logIpc'; class DesktopMain extends Disposable { @@ -153,7 +153,7 @@ class DesktopMain extends Disposable { serviceCollection.set(IProductService, this.productService); // Logger - const loggerService = new LoggerService(mainProcessService); + const loggerService = new LoggerChannelClient(mainProcessService.getChannel('logger')); serviceCollection.set(ILoggerService, loggerService); // Log diff --git a/src/vs/workbench/services/log/electron-sandbox/logService.ts b/src/vs/workbench/services/log/electron-sandbox/logService.ts index e9f19330624..4ace2bc3fba 100644 --- a/src/vs/workbench/services/log/electron-sandbox/logService.ts +++ b/src/vs/workbench/services/log/electron-sandbox/logService.ts @@ -5,14 +5,13 @@ import { LogService, ConsoleLogger, MultiplexLogService, ILogger } from 'vs/platform/log/common/log'; import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; -import { LogLevelChannelClient, FollowerLogService } from 'vs/platform/log/common/logIpc'; +import { LogLevelChannelClient, FollowerLogService, LoggerChannelClient } from 'vs/platform/log/common/logIpc'; import { DisposableStore } from 'vs/base/common/lifecycle'; -import { LoggerService } from 'vs/workbench/services/log/electron-sandbox/loggerService'; import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services'; export class NativeLogService extends LogService { - constructor(name: string, loggerService: LoggerService, mainProcessService: IMainProcessService, environmentService: INativeWorkbenchEnvironmentService) { + constructor(name: string, loggerService: LoggerChannelClient, mainProcessService: IMainProcessService, environmentService: INativeWorkbenchEnvironmentService) { const disposables = new DisposableStore(); const loggerClient = new LogLevelChannelClient(mainProcessService.getChannel('logLevel')); diff --git a/src/vs/workbench/services/log/electron-sandbox/loggerService.ts b/src/vs/workbench/services/log/electron-sandbox/loggerService.ts deleted file mode 100644 index fbe8bc70033..00000000000 --- a/src/vs/workbench/services/log/electron-sandbox/loggerService.ts +++ /dev/null @@ -1,61 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IChannel } from 'vs/base/parts/ipc/common/ipc'; -import { LogLevel, ILoggerService, ILogger, AbstractMessageLogger, ILoggerOptions } from 'vs/platform/log/common/log'; -import { URI } from 'vs/base/common/uri'; -import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services'; - -export class LoggerService implements ILoggerService { - - declare readonly _serviceBrand: undefined; - private readonly channel: IChannel; - - constructor( - @IMainProcessService mainProcessService: IMainProcessService - ) { - this.channel = mainProcessService.getChannel('logger'); - } - - createConsoleMainLogger(): ILogger { - return new Logger(this.channel); - } - - createLogger(file: URI, options?: ILoggerOptions): ILogger { - return new Logger(this.channel, file, options); - } - -} - -class Logger extends AbstractMessageLogger { - - private isLoggerCreated: boolean = false; - private buffer: [LogLevel, string][] = []; - - constructor( - private readonly channel: IChannel, - private readonly file?: URI, - loggerOptions?: ILoggerOptions, - ) { - super(loggerOptions?.always); - (this.file ? this.channel.call('createLogger', [file, loggerOptions]) : this.channel.call('createConsoleLogger', [file, loggerOptions])) - .then(() => { - this._log(this.buffer); - this.isLoggerCreated = true; - }); - } - - protected log(level: LogLevel, message: string) { - this._log([[level, message]]); - } - - private _log(messages: [LogLevel, string][]) { - if (this.isLoggerCreated) { - this.channel.call('log', [this.file, messages]); - } else { - this.buffer.push(...messages); - } - } -} From 2a1f11a296ba184103faf85e74142013a5f359e1 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 18 Feb 2021 12:14:22 +0100 Subject: [PATCH 310/325] add IResolvedNotebookEditorModel and use that in most places so that we can remove non-null assertions --- .../browser/notebookDiffEditorInput.ts | 23 ++--- .../notebook/browser/notebookEditorInput.ts | 6 +- .../contrib/notebook/common/notebookCommon.ts | 19 +++- .../notebook/common/notebookEditorModel.ts | 97 ++++++++++--------- .../notebookEditorModelResolverService.ts | 14 +-- .../notebook/test/testNotebookEditor.ts | 6 +- 6 files changed, 95 insertions(+), 70 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/notebookDiffEditorInput.ts b/src/vs/workbench/contrib/notebook/browser/notebookDiffEditorInput.ts index 8442f6e3781..604cad0e755 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookDiffEditorInput.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookDiffEditorInput.ts @@ -12,8 +12,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService'; import { IReference } from 'vs/base/common/lifecycle'; -import { INotebookEditorModel, INotebookDiffEditorModel } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -import { NotebookEditorModel } from 'vs/workbench/contrib/notebook/common/notebookEditorModel'; +import { INotebookDiffEditorModel, IResolvedNotebookEditorModel } from 'vs/workbench/contrib/notebook/common/notebookCommon'; interface NotebookEditorInputOptions { startDirty?: boolean; @@ -21,8 +20,8 @@ interface NotebookEditorInputOptions { class NotebookDiffEditorModel extends EditorModel implements INotebookDiffEditorModel { constructor( - readonly original: NotebookEditorModel, - readonly modified: NotebookEditorModel, + readonly original: IResolvedNotebookEditorModel, + readonly modified: IResolvedNotebookEditorModel, ) { super(); } @@ -54,8 +53,8 @@ export class NotebookDiffEditorInput extends EditorInput { static readonly ID: string = 'workbench.input.diffNotebookInput'; - private _textModel: IReference | null = null; - private _originalTextModel: IReference | null = null; + private _textModel: IReference | null = null; + private _originalTextModel: IReference | null = null; private _defaultDirtyState: boolean = false; constructor( @@ -186,10 +185,12 @@ ${patterns} if (!this._textModel) { this._textModel = await this._notebookModelResolverService.resolve(this.resource, this.viewType!); + } + if (!this._originalTextModel) { this._originalTextModel = await this._notebookModelResolverService.resolve(this.originalResource, this.viewType!); } - return new NotebookDiffEditorModel(this._originalTextModel!.object as NotebookEditorModel, this._textModel.object as NotebookEditorModel); + return new NotebookDiffEditorModel(this._originalTextModel.object, this._textModel.object); } matches(otherInput: unknown): boolean { @@ -204,10 +205,10 @@ ${patterns} } dispose() { - if (this._textModel) { - this._textModel.dispose(); - this._textModel = null; - } + this._textModel?.dispose(); + this._textModel = null; + this._originalTextModel?.dispose(); + this._originalTextModel = null; super.dispose(); } } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorInput.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorInput.ts index cd68acce0ec..dd6cb29677a 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorInput.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorInput.ts @@ -12,7 +12,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService'; import { IReference } from 'vs/base/common/lifecycle'; -import { INotebookEditorModel } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { IResolvedNotebookEditorModel } from 'vs/workbench/contrib/notebook/common/notebookCommon'; interface NotebookEditorInputOptions { startDirty?: boolean; @@ -25,7 +25,7 @@ export class NotebookEditorInput extends EditorInput { static readonly ID: string = 'workbench.input.notebook'; - private _textModel: IReference | null = null; + private _textModel: IReference | null = null; private _defaultDirtyState: boolean = false; constructor( @@ -153,7 +153,7 @@ ${patterns} return; } - async resolve(): Promise { + async resolve(): Promise { if (!await this._notebookService.canResolve(this.viewType!)) { return null; } diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index 8196d8ac5f2..d9592bd84b8 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -596,22 +596,35 @@ export const NOTEBOOK_EDITOR_CURSOR_BOUNDARY = new RawContextKey<'none' | 'top' export const NOTEBOOK_EDITOR_CURSOR_BEGIN_END = new RawContextKey('notebookEditorCursorAtEditorBeginEnd', false); +export interface INotebookLoadOptions { + /** + * Go to disk bypassing any cache of the model if any. + */ + forceReadFromDisk?: boolean; +} + +export interface IResolvedNotebookEditorModel extends INotebookEditorModel { + notebook: NotebookTextModel; +} + export interface INotebookEditorModel extends IEditorModel { readonly onDidChangeDirty: Event; readonly resource: URI; readonly viewType: string; - readonly notebook: NotebookTextModel; + readonly notebook: NotebookTextModel | undefined; readonly lastResolvedFileStat: IFileStatWithMetadata | undefined; + isResolved(): this is IResolvedNotebookEditorModel; isDirty(): boolean; isUntitled(): boolean; + load(options?: INotebookLoadOptions): Promise; save(): Promise; saveAs(target: URI): Promise; revert(options?: IRevertOptions | undefined): Promise; } export interface INotebookDiffEditorModel extends IEditorModel { - original: INotebookEditorModel; - modified: INotebookEditorModel; + original: IResolvedNotebookEditorModel; + modified: IResolvedNotebookEditorModel; resolveOriginalFromDisk(): Promise; resolveModifiedFromDisk(): Promise; } diff --git a/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts b/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts index 583dad5a8cf..67a7f526560 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { EditorModel, IRevertOptions } from 'vs/workbench/common/editor'; import { Emitter, Event } from 'vs/base/common/event'; -import { INotebookEditorModel, NotebookCellsChangeType, NotebookDocumentBackupData } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookEditorModel, INotebookLoadOptions, IResolvedNotebookEditorModel, NotebookCellsChangeType, NotebookDocumentBackupData } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { URI } from 'vs/base/common/uri'; @@ -19,15 +19,7 @@ import { INotificationService, Severity } from 'vs/platform/notification/common/ import { ILabelService } from 'vs/platform/label/common/label'; import { ILogService } from 'vs/platform/log/common/log'; import { TaskSequentializer } from 'vs/base/common/async'; - - -export interface INotebookLoadOptions { - /** - * Go to disk bypassing any cache of the model if any. - */ - forceReadFromDisk?: boolean; -} - +import { assertType } from 'vs/base/common/types'; export class NotebookEditorModel extends EditorModel implements INotebookEditorModel { @@ -37,14 +29,14 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM readonly onDidChangeDirty = this._onDidChangeDirty.event; readonly onDidChangeContent = this._onDidChangeContent.event; - private _notebook!: NotebookTextModel; + private _notebook?: NotebookTextModel; private _lastResolvedFileStat?: IFileStatWithMetadata; private readonly _name: string; private readonly _workingCopyResource: URI; - private readonly saveSequentializer = new TaskSequentializer(); + private readonly _saveSequentializer = new TaskSequentializer(); - private _dirty = false; + private _dirty: boolean = false; constructor( readonly resource: URI, @@ -78,11 +70,23 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM this._register(this._workingCopyService.registerWorkingCopy(workingCopyAdapter)); } - get lastResolvedFileStat() { + isResolved(): this is IResolvedNotebookEditorModel { + return this.notebook !== undefined; + } + + isDirty(): boolean { + return this._dirty; + } + + isUntitled(): boolean { + return this.resource.scheme === Schemas.untitled; + } + + get lastResolvedFileStat(): IFileStatWithMetadata | undefined { return this._lastResolvedFileStat; } - get notebook() { + get notebook(): NotebookTextModel | undefined { return this._notebook; } @@ -94,7 +98,12 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM } async backup(token: CancellationToken): Promise> { - if (this._notebook.supportBackup) { + + if (!this.isResolved()) { + throw new Error('CANNOT call backup before notebook is resolved'); + } + + if (this.notebook.supportBackup) { const tokenSource = new CancellationTokenSource(token); const backupId = await this._notebookService.backup(this.viewType, this.resource, tokenSource.token); if (token.isCancellationRequested) { @@ -106,7 +115,7 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM meta: { mtime: stats?.mtime || new Date().getTime(), name: this._name, - viewType: this._notebook.viewType, + viewType: this.notebook.viewType, backupId: backupId } }; @@ -115,9 +124,9 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM meta: { mtime: new Date().getTime(), name: this._name, - viewType: this._notebook.viewType + viewType: this.notebook.viewType }, - content: this._notebook.createSnapshot(true) + content: this.notebook.createSnapshot(true) }; } } @@ -137,7 +146,7 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM this._onDidChangeDirty.fire(); } - async load(options?: INotebookLoadOptions): Promise { + async load(options?: INotebookLoadOptions): Promise { if (options?.forceReadFromDisk) { return this._loadFromProvider(true, undefined); } @@ -155,11 +164,10 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM return this._loadFromProvider(false, backup?.meta?.backupId); } - private async _loadFromProvider(forceReloadFromDisk: boolean, backupId: string | undefined) { - this._notebook = await this._notebookService.resolveNotebook(this.viewType!, this.resource, forceReloadFromDisk, backupId); + private async _loadFromProvider(forceReloadFromDisk: boolean, backupId: string | undefined): Promise { - const newStats = await this._resolveStats(this.resource); - this._lastResolvedFileStat = newStats; + this._notebook = await this._notebookService.resolveNotebook(this.viewType, this.resource, forceReloadFromDisk, backupId); + this._lastResolvedFileStat = await this._resolveStats(this.resource); this._register(this._notebook); @@ -185,22 +193,10 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM await this._backupFileService.discardBackup(this._workingCopyResource); this.setDirty(true); } - + assertType(this.isResolved()); return this; } - isResolved(): boolean { - return !!this._notebook; - } - - isDirty() { - return this._dirty; - } - - isUntitled() { - return this.resource.scheme === Schemas.untitled; - } - private async _assertStat() { this._logService.debug('[notebook editor model] start assert stat'); const stats = await this._resolveStats(this.resource); @@ -241,35 +237,41 @@ Current stat: ${JSON.stringify(stats)} } async save(): Promise { - let versionId = this._notebook.versionId; + + if (!this.isResolved()) { + return false; + } + + const versionId = this.notebook.versionId; this._logService.debug(`[notebook editor model] save(${versionId}) - enter with versionId ${versionId}`, this.resource.toString(true)); - if (this.saveSequentializer.hasPending(versionId)) { + if (this._saveSequentializer.hasPending(versionId)) { this._logService.debug(`[notebook editor model] save(${versionId}) - exit - found a pending save for versionId ${versionId}`, this.resource.toString(true)); - return this.saveSequentializer.pending.then(() => { + return this._saveSequentializer.pending.then(() => { return true; }); } - if (this.saveSequentializer.hasPending()) { - return this.saveSequentializer.setNext(async () => { + if (this._saveSequentializer.hasPending()) { + return this._saveSequentializer.setNext(async () => { await this.save(); }).then(() => { return true; }); } - return this.saveSequentializer.setPending(versionId, (async () => { + return this._saveSequentializer.setPending(versionId, (async () => { const result = await this._assertStat(); if (result === 'none') { return; } - if (result === 'revert') { await this.revert(); return; } - + if (!this.isResolved()) { + return; + } const tokenSource = new CancellationTokenSource(); await this._notebookService.save(this.notebook.viewType, this.notebook.uri, tokenSource.token); this._logService.debug(`[notebook editor model] save(${versionId}) - document saved saved, start updating file stats`, this.resource.toString(true)); @@ -282,6 +284,11 @@ Current stat: ${JSON.stringify(stats)} } async saveAs(targetResource: URI): Promise { + + if (!this.isResolved()) { + return false; + } + this._logService.debug(`[notebook editor model] saveAs - enter`, this.resource.toString(true)); const result = await this._assertStat(); diff --git a/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverService.ts b/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverService.ts index ace31e6a1b4..85a19e97356 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverService.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverService.ts @@ -5,7 +5,7 @@ import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { URI } from 'vs/base/common/uri'; -import { CellUri, INotebookEditorModel } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellUri, IResolvedNotebookEditorModel } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookEditorModel } from 'vs/workbench/contrib/notebook/common/notebookEditorModel'; import { combinedDisposable, DisposableStore, IDisposable, IReference, ReferenceCollection } from 'vs/base/common/lifecycle'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; @@ -16,11 +16,11 @@ export const INotebookEditorModelResolverService = createDecorator>; + resolve(resource: URI, viewType?: string): Promise>; } -export class NotebookModelReferenceCollection extends ReferenceCollection> { +export class NotebookModelReferenceCollection extends ReferenceCollection> { constructor( @IInstantiationService readonly _instantiationService: IInstantiationService, @@ -30,14 +30,14 @@ export class NotebookModelReferenceCollection extends ReferenceCollection { + protected createReferencedObject(key: string, viewType: string): Promise { const uri = URI.parse(key); const model = this._instantiationService.createInstance(NotebookEditorModel, uri, viewType); const promise = model.load(); return promise; } - protected destroyReferencedObject(_key: string, object: Promise): void { + protected destroyReferencedObject(_key: string, object: Promise): void { object.then(model => { this._notebookService.destoryNotebookDocument(model.viewType, model.notebook); model.dispose(); @@ -60,7 +60,7 @@ export class NotebookModelResolverService implements INotebookEditorModelResolve this._data = instantiationService.createInstance(NotebookModelReferenceCollection); } - async resolve(resource: URI, viewType?: string): Promise> { + async resolve(resource: URI, viewType?: string): Promise> { if (resource.scheme === CellUri.scheme) { throw new Error(`CANNOT open a cell-uri as notebook. Tried with ${resource.toString()}`); } @@ -96,7 +96,7 @@ export class NotebookModelResolverService implements INotebookEditorModelResolve }; } - private static _autoReferenceDirtyModel(model: INotebookEditorModel, ref: () => IDisposable): IDisposable { + private static _autoReferenceDirtyModel(model: IResolvedNotebookEditorModel, ref: () => IDisposable): IDisposable { const references = new DisposableStore(); const listener = model.onDidChangeDirty(() => { diff --git a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts index 3c7419a8563..5614be8731e 100644 --- a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts @@ -18,7 +18,7 @@ import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/v import { CellViewModel, IModelDecorationsChangeAccessor, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; -import { CellKind, CellUri, INotebookEditorModel, NotebookCellMetadata, ICellRange, INotebookKernel, notebookDocumentMetadataDefaults, IOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, CellUri, INotebookEditorModel, NotebookCellMetadata, ICellRange, INotebookKernel, notebookDocumentMetadataDefaults, IOutputDto, IResolvedNotebookEditorModel } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { Webview } from 'vs/workbench/contrib/webview/browser/webview'; import { ICompositeCodeEditor, IEditor } from 'vs/editor/common/editorCommon'; import { NotImplementedError } from 'vs/base/common/errors'; @@ -416,6 +416,10 @@ export class NotebookEditorTestModel extends EditorModel implements INotebookEdi return this._notebook; } + async load(): Promise { + return this; + } + async save(): Promise { if (this._notebook) { this._dirty = false; From 7d74c5d4b050909f96812fff788faf5a5ef32882 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 18 Feb 2021 12:14:40 +0100 Subject: [PATCH 311/325] :lipstick: --- src/vs/workbench/contrib/notebook/browser/notebookEditor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts index 1025ccaf67b..7128a683466 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts @@ -173,7 +173,7 @@ export class NotebookEditor extends EditorPane { label: localize('fail.reOpen', "Reopen file with VS Code standard text editor"), run: async () => { const fileEditorInput = this._editorService.createEditorInput({ resource: input.resource, forceFile: true }); - const textOptions: IEditorOptions | ITextEditorOptions = options ? { ...options, override: false } : { override: false }; + const textOptions: IEditorOptions | ITextEditorOptions = { ...options, override: false }; await this._editorService.openEditor(fileEditorInput, textOptions); } }] From 31e3a7794d4db726400f34cdcc0e39aa891e6e72 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 18 Feb 2021 14:16:16 +0100 Subject: [PATCH 312/325] merge NotebookController#reloadNotebook into notebook editor model, remove NotebookServce#resolve and add create and fetchData "primitives", https://github.com/microsoft/vscode/issues/114263 --- .../api/browser/mainThreadNotebook.ts | 18 +---- .../notebook/browser/notebookServiceImpl.ts | 46 +++-------- .../common/model/notebookTextModel.ts | 2 +- .../notebook/common/notebookEditorModel.ts | 80 ++++++++++++++----- .../notebook/common/notebookService.ts | 12 ++- 5 files changed, 81 insertions(+), 77 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts index ef5198afafe..fe1b377f5e0 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as DOM from 'vs/base/browser/dom'; import { CancellationToken } from 'vs/base/common/cancellation'; import { diffMaps, diffSets } from 'vs/base/common/collections'; import { Emitter } from 'vs/base/common/event'; @@ -24,7 +23,7 @@ import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookB import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService'; -import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, DisplayOrderKey, ICellEditOperation, ICellRange, IEditor, IMainCellDto, INotebookDecorationRenderOptions, INotebookDocumentFilter, INotebookEditorModel, INotebookExclusiveDocumentFilter, INotebookKernel, NotebookCellsChangeType, NOTEBOOK_DISPLAY_ORDER, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, DisplayOrderKey, ICellEditOperation, ICellRange, IEditor, IMainCellDto, INotebookDecorationRenderOptions, INotebookDocumentFilter, INotebookEditorModel, INotebookExclusiveDocumentFilter, INotebookKernel, NotebookCellsChangeType, NOTEBOOK_DISPLAY_ORDER, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService'; import { IMainNotebookController, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IEditorGroup, IEditorGroupsService, preferredSideBySideGroupDirection } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -479,21 +478,6 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo contentOptions.transientOutputs = newOptions.transientOutputs; }, viewOptions: options.viewOptions, - reloadNotebook: async (mainthreadTextModel: NotebookTextModel) => { - const data = await this._proxy.$openNotebook(viewType, mainthreadTextModel.uri); - mainthreadTextModel.metadata = data.metadata; - mainthreadTextModel.transientOptions = contentOptions; - - const edits: ICellEditOperation[] = [ - { editType: CellEditType.Replace, index: 0, count: mainthreadTextModel.cells.length, cells: data.cells } - ]; - await new Promise(resolve => { - DOM.scheduleAtNextAnimationFrame(() => { - const ret = mainthreadTextModel!.applyEdits(mainthreadTextModel!.versionId, edits, true, undefined, () => undefined, undefined); - resolve(ret); - }); - }); - }, openNotebook: async (viewType: string, uri: URI, backupId?: string) => { const data = await this._proxy.$openNotebook(viewType, uri, backupId); return { diff --git a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts index 5049ff03ab4..4c2d3e0c6ad 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts @@ -10,7 +10,6 @@ import { Emitter, Event } from 'vs/base/common/event'; import { Iterable } from 'vs/base/common/iterator'; import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { ResourceMap } from 'vs/base/common/map'; -import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; import * as UUID from 'vs/base/common/uuid'; import { RedoCommand, UndoCommand } from 'vs/editor/browser/editorExtensions'; @@ -32,7 +31,7 @@ import { NotebookKernelProviderAssociationRegistry, NotebookViewTypesExtensionRe import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; -import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, BUILTIN_RENDERER_ID, CellEditType, CellKind, DisplayOrderKey, ICellEditOperation, INotebookDecorationRenderOptions, INotebookKernel, INotebookKernelProvider, INotebookMarkdownRendererInfo, INotebookRendererInfo, INotebookTextModel, IOrderedMimeType, IOutputDto, mimeTypeIsAlwaysSecure, mimeTypeSupportedByCore, notebookDocumentFilterMatch, NotebookEditorPriority, NOTEBOOK_DISPLAY_ORDER, RENDERER_NOT_AVAILABLE, sortMimeTypes } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, BUILTIN_RENDERER_ID, CellEditType, CellKind, DisplayOrderKey, ICellEditOperation, INotebookDecorationRenderOptions, INotebookKernel, INotebookKernelProvider, INotebookMarkdownRendererInfo, INotebookRendererInfo, INotebookTextModel, IOrderedMimeType, IOutputDto, mimeTypeIsAlwaysSecure, mimeTypeSupportedByCore, NotebookDataDto, notebookDocumentFilterMatch, NotebookEditorPriority, NOTEBOOK_DISPLAY_ORDER, RENDERER_NOT_AVAILABLE, sortMimeTypes, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookMarkdownRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookMarkdownRenderer'; import { NotebookOutputRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookOutputRenderer'; import { NotebookEditorDescriptor, NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider'; @@ -751,45 +750,22 @@ export class NotebookService extends Disposable implements INotebookService, ICu return Array.from(this.markdownRenderersInfos); } - async resolveNotebook(viewType: string, uri: URI, forceReload: boolean, backupId?: string): Promise { - + async fetchNotebookRawData(viewType: string, uri: URI, backupId?: string): Promise<{ data: NotebookDataDto, transientOptions: TransientOptions }> { if (!await this.canResolve(viewType)) { - throw new Error(`CANNOT load notebook, no provider for '${viewType}'`); + throw new Error(`CANNOT fetch notebook data, there is NO provider for '${viewType}'`); } - const provider = this._notebookProviders.get(viewType)!; - let notebookModel: NotebookTextModel; + return await provider.controller.openNotebook(viewType, uri, backupId); + } + + createNotebookTextModel(viewType: string, uri: URI, data: NotebookDataDto, transientOptions: TransientOptions): NotebookTextModel { if (this._models.has(uri)) { - // the model already exists - notebookModel = this._models.get(uri)!.model; - if (forceReload) { - await provider.controller.reloadNotebook(notebookModel); - } - return notebookModel; - - } else { - const dataDto = await provider.controller.openNotebook(viewType, uri, backupId); - let cells = dataDto.data.cells.length ? dataDto.data.cells : (uri.scheme === Schemas.untitled ? [{ - cellKind: CellKind.Code, - language: 'plaintext', //TODO@jrieken unsure what this is - outputs: [], - metadata: undefined, - source: '' - }] : []); - - notebookModel = this._instantiationService.createInstance(NotebookTextModel, viewType, provider.controller.supportBackup, uri, cells, dataDto.data.metadata, dataDto.transientOptions); + throw new Error(`notebook for ${uri} already exists`); } - - // new notebook model created - const modelData = new ModelData( - notebookModel, - (model) => this._onWillDisposeDocument(model), - ); - - this._models.set(uri, modelData); + const notebookModel = this._instantiationService.createInstance(NotebookTextModel, viewType, true, uri, data.cells, data.metadata, transientOptions); + this._models.set(uri, new ModelData(notebookModel, this._onWillDisposeDocument.bind(this))); this._onDidAddNotebookDocument.fire(notebookModel); - - return modelData.model; + return notebookModel; } getNotebookTextModel(uri: URI): NotebookTextModel | undefined { diff --git a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts index 5d5364651e5..ad138d44321 100644 --- a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts +++ b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts @@ -229,7 +229,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel constructor( readonly viewType: string, - readonly supportBackup: boolean, + readonly supportBackup: boolean, //TODO@jrieken,@rebornix all support backup, right? readonly uri: URI, cells: ICellDto2[], metadata: NotebookDocumentMetadata, diff --git a/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts b/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts index 67a7f526560..59561937ffc 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { EditorModel, IRevertOptions } from 'vs/workbench/common/editor'; import { Emitter, Event } from 'vs/base/common/event'; -import { INotebookEditorModel, INotebookLoadOptions, IResolvedNotebookEditorModel, NotebookCellsChangeType, NotebookDocumentBackupData } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellEditType, CellKind, ICellEditOperation, INotebookEditorModel, INotebookLoadOptions, IResolvedNotebookEditorModel, NotebookCellsChangeType, NotebookDocumentBackupData } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { URI } from 'vs/base/common/uri'; @@ -29,7 +29,6 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM readonly onDidChangeDirty = this._onDidChangeDirty.event; readonly onDidChangeContent = this._onDidChangeContent.event; - private _notebook?: NotebookTextModel; private _lastResolvedFileStat?: IFileStatWithMetadata; private readonly _name: string; @@ -87,7 +86,8 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM } get notebook(): NotebookTextModel | undefined { - return this._notebook; + const candidate = this._notebookService.getNotebookTextModel(this.resource); + return candidate && candidate.viewType === this.viewType ? candidate : undefined; } setDirty(newState: boolean) { @@ -148,7 +148,7 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM async load(options?: INotebookLoadOptions): Promise { if (options?.forceReadFromDisk) { - return this._loadFromProvider(true, undefined); + return this._loadFromProvider(undefined); } if (this.isResolved()) { @@ -161,37 +161,73 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM return this; // Make sure meanwhile someone else did not succeed in loading } - return this._loadFromProvider(false, backup?.meta?.backupId); + return this._loadFromProvider(backup?.meta?.backupId); } - private async _loadFromProvider(forceReloadFromDisk: boolean, backupId: string | undefined): Promise { + private async _loadFromProvider(backupId: string | undefined): Promise { - this._notebook = await this._notebookService.resolveNotebook(this.viewType, this.resource, forceReloadFromDisk, backupId); + const data = await this._notebookService.fetchNotebookRawData(this.viewType, this.resource, backupId); this._lastResolvedFileStat = await this._resolveStats(this.resource); - this._register(this._notebook); + if (this.isDisposed()) { + // todo@jrieken ugly... we have been disposed which means we cannot return anything... + return this as any; + } - this._register(this._notebook.onDidChangeContent(e => { - let triggerDirty = false; - for (let i = 0; i < e.rawEvents.length; i++) { - if (e.rawEvents[i].kind !== NotebookCellsChangeType.Initialize) { - this._onDidChangeContent.fire(); - triggerDirty = triggerDirty || !e.rawEvents[i].transient; + if (!this.notebook) { + // FRESH there is no notebook yet and we are now creating it + + // UGLY + // There might be another notebook for the URI which was created from a different + // source (different viewType). In that case we simply dispose the + // existing/conflicting model and proceed with a new notebook + const conflictingNotebook = this._notebookService.getNotebookTextModel(this.resource); + if (conflictingNotebook) { + this._logService.warn('DISPOSING conflicting notebook with same URI but different view type', this.resource.toString(), this.viewType); + conflictingNotebook.dispose(); + } + + // todo@jrieken@rebornix what about reload? + if (this.resource.scheme === Schemas.untitled && data.data.cells.length === 0) { + data.data.cells.push({ + cellKind: CellKind.Code, + language: 'plaintext', //TODO@jrieken unsure what this is + outputs: [], + metadata: undefined, + source: '' + }); + } + + // this creates and caches a new notebook model so that notebookService.getNotebookTextModel(...) + // will return this one model + const notebook = this._notebookService.createNotebookTextModel(this.viewType, this.resource, data.data, data.transientOptions); + this._register(notebook); + this._register(notebook.onDidChangeContent(e => { + let triggerDirty = false; + for (let i = 0; i < e.rawEvents.length; i++) { + if (e.rawEvents[i].kind !== NotebookCellsChangeType.Initialize) { + this._onDidChangeContent.fire(); + triggerDirty = triggerDirty || !e.rawEvents[i].transient; + } } - } + if (triggerDirty) { + this.setDirty(true); + } + })); - if (triggerDirty) { - this.setDirty(true); - } - })); - - if (forceReloadFromDisk) { - this.setDirty(false); + } else { + // UPDATE exitsing notebook with data that we have just fetched + this.notebook.metadata = data.data.metadata; + this.notebook.transientOptions = data.transientOptions; + const edits: ICellEditOperation[] = [{ editType: CellEditType.Replace, index: 0, count: data.data.cells.length, cells: data.data.cells }]; + this.notebook.applyEdits(this.notebook.versionId, edits, true, undefined, () => undefined, undefined); } if (backupId) { await this._backupFileService.discardBackup(this._workingCopyResource); this.setDirty(true); + } else { + this.setDirty(false); } assertType(this.isResolved()); return this; diff --git a/src/vs/workbench/contrib/notebook/common/notebookService.ts b/src/vs/workbench/contrib/notebook/common/notebookService.ts index c8cdc11f85a..f25bea8de6f 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookService.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookService.ts @@ -24,7 +24,6 @@ export interface IMainNotebookController { viewOptions?: { displayName: string; filenamePattern: (string | IRelativePattern | INotebookExclusiveDocumentFilter)[]; exclusive: boolean; }; options: { transientOutputs: boolean; transientMetadata: TransientMetadata; }; openNotebook(viewType: string, uri: URI, backupId?: string): Promise<{ data: NotebookDataDto, transientOptions: TransientOptions; }>; - reloadNotebook(mainthreadTextModel: NotebookTextModel): Promise; resolveNotebookEditor(viewType: string, uri: URI, editorId: string): Promise; onDidReceiveMessage(editorId: string, rendererType: string | undefined, message: any): void; save(uri: URI, token: CancellationToken): Promise; @@ -32,6 +31,12 @@ export interface IMainNotebookController { backup(uri: URI, token: CancellationToken): Promise; } + +export interface INotebookRawData { + data: NotebookDataDto; + transientOptions: TransientOptions; +} + export interface INotebookService { readonly _serviceBrand: undefined; canResolve(viewType: string): Promise; @@ -55,7 +60,7 @@ export interface INotebookService { getRendererInfo(id: string): INotebookRendererInfo | undefined; getMarkdownRendererInfo(): INotebookMarkdownRendererInfo[]; - resolveNotebook(viewType: string, uri: URI, forceReload: boolean, backupId?: string): Promise; + createNotebookTextModel(viewType: string, uri: URI, data: NotebookDataDto, transientOptions: TransientOptions): NotebookTextModel; getNotebookTextModel(uri: URI): NotebookTextModel | undefined; getNotebookTextModels(): Iterable; getContributedNotebookProviders(resource?: URI): readonly NotebookProviderInfo[]; @@ -64,9 +69,12 @@ export interface INotebookService { destoryNotebookDocument(viewType: string, notebook: INotebookTextModel): void; updateActiveNotebookEditor(editor: IEditor | null): void; updateVisibleNotebookEditor(editors: string[]): void; + + fetchNotebookRawData(viewType: string, uri: URI, backupId?: string): Promise; save(viewType: string, resource: URI, token: CancellationToken): Promise; saveAs(viewType: string, resource: URI, target: URI, token: CancellationToken): Promise; backup(viewType: string, uri: URI, token: CancellationToken): Promise; + onDidReceiveMessage(viewType: string, editorId: string, rendererType: string | undefined, message: unknown): void; setToCopy(items: NotebookCellTextModel[], isCopy: boolean): void; getToCopy(): { items: NotebookCellTextModel[], isCopy: boolean; } | undefined; From ecd60db25052157c3a96070b01eda3ecdce1a5f2 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 18 Feb 2021 15:28:55 +0100 Subject: [PATCH 313/325] reload non-dirty notebooks when their files change on disk, https://github.com/microsoft/vscode/issues/114263 --- .../notebook/common/notebookEditorModel.ts | 54 +++++++++++-------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts b/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts index 59561937ffc..ab43d00fc11 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts @@ -14,7 +14,7 @@ import { IWorkingCopyService, IWorkingCopy, IWorkingCopyBackup, WorkingCopyCapab import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { Schemas } from 'vs/base/common/network'; -import { IFileStatWithMetadata, IFileService } from 'vs/platform/files/common/files'; +import { IFileStatWithMetadata, IFileService, FileChangeType } from 'vs/platform/files/common/files'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { ILabelService } from 'vs/platform/label/common/label'; import { ILogService } from 'vs/platform/log/common/log'; @@ -67,6 +67,20 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM }; this._register(this._workingCopyService.registerWorkingCopy(workingCopyAdapter)); + this._register(this._fileService.onDidFilesChange(async e => { + if (this.isDirty() || !this.isResolved()) { + // skip when dirty or unresolved... + return; + } + if (!e.affects(this.resource, FileChangeType.UPDATED)) { + // no my file + return; + } + const stats = await this._resolveStats(this.resource); + if (stats && this._lastResolvedFileStat && stats.etag !== this._lastResolvedFileStat.etag) { + this.load({ forceReadFromDisk: true }); + } + })); } isResolved(): this is IResolvedNotebookEditorModel { @@ -148,7 +162,9 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM async load(options?: INotebookLoadOptions): Promise { if (options?.forceReadFromDisk) { - return this._loadFromProvider(undefined); + this._loadFromProvider(undefined); + assertType(this.isResolved()); + return this; } if (this.isResolved()) { @@ -161,17 +177,18 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM return this; // Make sure meanwhile someone else did not succeed in loading } - return this._loadFromProvider(backup?.meta?.backupId); + await this._loadFromProvider(backup?.meta?.backupId); + assertType(this.isResolved()); + return this; } - private async _loadFromProvider(backupId: string | undefined): Promise { + private async _loadFromProvider(backupId: string | undefined): Promise { const data = await this._notebookService.fetchNotebookRawData(this.viewType, this.resource, backupId); this._lastResolvedFileStat = await this._resolveStats(this.resource); if (this.isDisposed()) { - // todo@jrieken ugly... we have been disposed which means we cannot return anything... - return this as any; + return; } if (!this.notebook) { @@ -219,28 +236,23 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM // UPDATE exitsing notebook with data that we have just fetched this.notebook.metadata = data.data.metadata; this.notebook.transientOptions = data.transientOptions; - const edits: ICellEditOperation[] = [{ editType: CellEditType.Replace, index: 0, count: data.data.cells.length, cells: data.data.cells }]; + const edits: ICellEditOperation[] = [{ editType: CellEditType.Replace, index: 0, count: this.notebook.cells.length, cells: data.data.cells }]; this.notebook.applyEdits(this.notebook.versionId, edits, true, undefined, () => undefined, undefined); } if (backupId) { - await this._backupFileService.discardBackup(this._workingCopyResource); + this._backupFileService.discardBackup(this._workingCopyResource); this.setDirty(true); } else { this.setDirty(false); } - assertType(this.isResolved()); - return this; } - private async _assertStat() { + private async _assertStat(): Promise<'overwrite' | 'revert' | 'none'> { this._logService.debug('[notebook editor model] start assert stat'); const stats = await this._resolveStats(this.resource); if (this._lastResolvedFileStat && stats && stats.mtime > this._lastResolvedFileStat.mtime) { - this._logService.debug(`[notebook editor model] noteboook file on disk is newer: -LastResolvedStat: ${this._lastResolvedFileStat ? JSON.stringify(this._lastResolvedFileStat) : undefined}. -Current stat: ${JSON.stringify(stats)} -`); + this._logService.debug(`[notebook editor model] noteboook file on disk is newer:\nLastResolvedStat: ${this._lastResolvedFileStat ? JSON.stringify(this._lastResolvedFileStat) : undefined}.\nCurrent stat: ${JSON.stringify(stats)}`); this._lastResolvedFileStat = stats; return new Promise<'overwrite' | 'revert' | 'none'>(resolve => { const handle = this._notificationService.prompt( @@ -308,11 +320,9 @@ Current stat: ${JSON.stringify(stats)} if (!this.isResolved()) { return; } - const tokenSource = new CancellationTokenSource(); - await this._notebookService.save(this.notebook.viewType, this.notebook.uri, tokenSource.token); + await this._notebookService.save(this.notebook.viewType, this.notebook.uri, CancellationToken.None); this._logService.debug(`[notebook editor model] save(${versionId}) - document saved saved, start updating file stats`, this.resource.toString(true)); - const newStats = await this._resolveStats(this.resource); - this._lastResolvedFileStat = newStats; + this._lastResolvedFileStat = await this._resolveStats(this.resource); this.setDirty(false); })()).then(() => { return true; @@ -337,11 +347,9 @@ Current stat: ${JSON.stringify(stats)} return true; } - const tokenSource = new CancellationTokenSource(); - await this._notebookService.saveAs(this.notebook.viewType, this.notebook.uri, targetResource, tokenSource.token); + await this._notebookService.saveAs(this.notebook.viewType, this.notebook.uri, targetResource, CancellationToken.None); this._logService.debug(`[notebook editor model] saveAs - document saved, start updating file stats`, this.resource.toString(true)); - const newStats = await this._resolveStats(this.resource); - this._lastResolvedFileStat = newStats; + this._lastResolvedFileStat = await this._resolveStats(this.resource); this.setDirty(false); return true; } From 29d4fdb65c8bae2001d1dc3178737127fde3d14d Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 18 Feb 2021 16:13:50 +0100 Subject: [PATCH 314/325] Fix #116829 --- src/vs/workbench/electron-sandbox/desktop.main.ts | 5 ++--- .../electron-sandbox/sandbox.simpleservices.ts | 11 +++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/electron-sandbox/desktop.main.ts b/src/vs/workbench/electron-sandbox/desktop.main.ts index d470723f747..7b045ab3243 100644 --- a/src/vs/workbench/electron-sandbox/desktop.main.ts +++ b/src/vs/workbench/electron-sandbox/desktop.main.ts @@ -35,7 +35,6 @@ import { FileUserDataProvider } from 'vs/workbench/services/userData/common/file import { basename } from 'vs/base/common/path'; import { IProductService } from 'vs/platform/product/common/productService'; import product from 'vs/platform/product/common/product'; -import { NativeLogService } from 'vs/workbench/services/log/electron-sandbox/logService'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { NativeHostService } from 'vs/platform/native/electron-sandbox/nativeHostService'; import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; @@ -43,7 +42,7 @@ import { UriIdentityService } from 'vs/workbench/services/uriIdentity/common/uri import { KeyboardLayoutService } from 'vs/workbench/services/keybinding/electron-sandbox/nativeKeyboardLayout'; import { IKeyboardLayoutService } from 'vs/platform/keyboardLayout/common/keyboardLayout'; import { ElectronIPCMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService'; -import { SimpleConfigurationService, simpleFileSystemProvider, SimpleSignService, SimpleNativeWorkbenchEnvironmentService, SimpleWorkspaceService } from 'vs/workbench/electron-sandbox/sandbox.simpleservices'; +import { SimpleConfigurationService, simpleFileSystemProvider, SimpleSignService, SimpleNativeWorkbenchEnvironmentService, SimpleWorkspaceService, SimpleLogService } from 'vs/workbench/electron-sandbox/sandbox.simpleservices'; import { LoggerChannelClient } from 'vs/platform/log/common/logIpc'; class DesktopMain extends Disposable { @@ -157,7 +156,7 @@ class DesktopMain extends Disposable { serviceCollection.set(ILoggerService, loggerService); // Log - const logService = this._register(new NativeLogService(`renderer${this.configuration.windowId}`, loggerService, mainProcessService, this.environmentService)); + const logService = new SimpleLogService(); serviceCollection.set(ILogService, logService); // Remote diff --git a/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts b/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts index 7b7312d9575..fb480250176 100644 --- a/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts +++ b/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts @@ -51,6 +51,7 @@ import { BrowserKeyboardLayoutService } from 'vs/workbench/services/keybinding/b import { TerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminalInstanceService'; import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { IWorkbenchConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; +import { ConsoleLogger, LogService } from 'vs/platform/log/common/log'; //#region Environment @@ -195,6 +196,16 @@ export class SimpleSignService implements ISignService { //#endregion +//#region Logger + +export class SimpleLogService extends LogService { + + constructor() { + super(new ConsoleLogger()); + } + +} + //#region Files From fba2cda1fa71bfee723cfc8876609a15be48e65c Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 18 Feb 2021 07:36:28 -0800 Subject: [PATCH 315/325] Handle non-responsive pty host process Fixes #116948 --- src/vs/platform/terminal/common/terminal.ts | 37 ++++++++- .../electron-browser/localPtyService.ts | 78 ++++++++++++++++--- .../terminal/node/heartbeatService.ts | 22 ++++++ src/vs/platform/terminal/node/ptyHostMain.ts | 11 ++- src/vs/platform/terminal/node/ptyService.ts | 3 + .../terminalInstanceService.ts | 12 ++- 6 files changed, 147 insertions(+), 16 deletions(-) create mode 100644 src/vs/platform/terminal/node/heartbeatService.ts diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index 77295d400e4..2f223fe786a 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -19,7 +19,11 @@ export enum TerminalIpcChannels { /** * Deals with logging from the pty host process. */ - Log = 'log' + Log = 'log', + /** + * Enables the detection of unresponsive pty hosts. + */ + Heartbeat = 'heartbeat' } export interface IPtyService { @@ -27,6 +31,7 @@ export interface IPtyService { readonly onPtyHostExit?: Event; readonly onPtyHostStart?: Event; + readonly onPtyHostUnresponsive?: Event; readonly onProcessData: Event<{ id: number, event: IProcessDataEvent | string }>; readonly onProcessExit: Event<{ id: number, event: number | undefined }>; @@ -62,6 +67,36 @@ export interface IPtyService { getCwd(id: number): Promise; getLatency(id: number): Promise; + + restartPtyHost?(): Promise; +} + +export enum HeartbeatConstants { + /** + * The duration between heartbeats + */ + BeatInterval = 10000, + /** + * Defines a multiplier for BeatInterval for how long to wait before starting the second wait + * timer. + */ + FirstWaitMultiplier = 1.2, + /** + * Defines a multiplier for BeatInterval for how long to wait before telling the user about + * non-responsiveness. The second timer is to avoid informing the user incorrectly when waking + * the computer up from sleep + */ + SecondWaitMultiplier = 1, + /** + * How long to wait before telling the user about non-responsiveness when they try to create a + * process. This short circuits the standard wait timeouts to tell the user sooner and only + * create process is handled to avoid additional perf overhead. + */ + CreateProcessTimeout = 3000 +} + +export interface IHeartbeatService { + readonly onBeat: Event; } export interface IShellLaunchConfig { diff --git a/src/vs/platform/terminal/electron-browser/localPtyService.ts b/src/vs/platform/terminal/electron-browser/localPtyService.ts index dfc72dc3b44..170058d1ab6 100644 --- a/src/vs/platform/terminal/electron-browser/localPtyService.ts +++ b/src/vs/platform/terminal/electron-browser/localPtyService.ts @@ -5,7 +5,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { ILogService } from 'vs/platform/log/common/log'; -import { IPtyService, IProcessDataEvent, IShellLaunchConfig, ITerminalDimensionsOverride, ITerminalLaunchError, TerminalIpcChannels } from 'vs/platform/terminal/common/terminal'; +import { IPtyService, IProcessDataEvent, IShellLaunchConfig, ITerminalDimensionsOverride, ITerminalLaunchError, TerminalIpcChannels, IHeartbeatService, HeartbeatConstants } from 'vs/platform/terminal/common/terminal'; import { Client } from 'vs/base/parts/ipc/node/ipc.cp'; import { FileAccess } from 'vs/base/common/network'; import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc'; @@ -20,16 +20,22 @@ enum Constants { export class LocalPtyService extends Disposable implements IPtyService { declare readonly _serviceBrand: undefined; + private _client: Client; // ProxyChannel is not used here because events get lost when forwarding across multiple proxies private _proxy: IPtyService; private _restartCount = 0; private _isDisposed = false; + private _heartbeatFirstTimeout?: NodeJS.Timeout; + private _heartbeatSecondTimeout?: NodeJS.Timeout; + private readonly _onPtyHostExit = this._register(new Emitter()); readonly onPtyHostExit = this._onPtyHostExit.event; private readonly _onPtyHostStart = this._register(new Emitter()); readonly onPtyHostStart = this._onPtyHostStart.event; + private readonly _onPtyHostUnresponsive = this._register(new Emitter()); + readonly onPtyHostUnresponsive = this._onPtyHostUnresponsive.event; private readonly _onProcessData = this._register(new Emitter<{ id: number, event: IProcessDataEvent | string }>()); readonly onProcessData = this._onProcessData.event; @@ -49,10 +55,10 @@ export class LocalPtyService extends Disposable implements IPtyService { ) { super(); - this._proxy = this._startPtyHost(); + [this._client, this._proxy] = this._startPtyHost(); } - private _startPtyHost(): IPtyService { + private _startPtyHost(): [Client, IPtyService] { const client = this._register(new Client( FileAccess.asFileUri('bootstrap-fork', require).fsPath, { @@ -67,13 +73,13 @@ export class LocalPtyService extends Disposable implements IPtyService { )); this._onPtyHostStart.fire(); + const heartbeatService = ProxyChannel.toService(client.getChannel(TerminalIpcChannels.Heartbeat)); + heartbeatService.onBeat(() => this._handleHeartbeat()); + // Handle exit this._register({ dispose: () => { - if (proxy.shutdownAll) { - proxy.shutdownAll(); - } - client.dispose(); + this._disposePtyHost(); } }); this._register(client.onDidProcessExit(e => { @@ -82,7 +88,7 @@ export class LocalPtyService extends Disposable implements IPtyService { if (this._restartCount <= Constants.MaxRestarts) { this._logService.error(`ptyHost terminated unexpectedly with code ${e.code}`); this._restartCount++; - this._proxy = this._startPtyHost(); + this.restartPtyHost(); } else { this._logService.error(`ptyHost terminated unexpectedly with code ${e.code}, giving up`); } @@ -103,7 +109,7 @@ export class LocalPtyService extends Disposable implements IPtyService { this._register(proxy.onProcessTitleChanged(e => this._onProcessTitleChanged.fire(e))); this._register(proxy.onProcessOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e))); this._register(proxy.onProcessResolvedShellLaunchConfig(e => this._onProcessResolvedShellLaunchConfig.fire(e))); - return proxy; + return [client, proxy]; } dispose() { @@ -111,8 +117,11 @@ export class LocalPtyService extends Disposable implements IPtyService { super.dispose(); } - createProcess(shellLaunchConfig: IShellLaunchConfig, cwd: string, cols: number, rows: number, env: IProcessEnvironment, executableEnv: IProcessEnvironment, windowsEnableConpty: boolean): Promise { - return this._proxy.createProcess(shellLaunchConfig, cwd, cols, rows, env, executableEnv, windowsEnableConpty); + async createProcess(shellLaunchConfig: IShellLaunchConfig, cwd: string, cols: number, rows: number, env: IProcessEnvironment, executableEnv: IProcessEnvironment, windowsEnableConpty: boolean): Promise { + const timeout = setTimeout(() => this._handleUnresponsiveCreateProcess(), HeartbeatConstants.CreateProcessTimeout); + const result = await this._proxy.createProcess(shellLaunchConfig, cwd, cols, rows, env, executableEnv, windowsEnableConpty); + clearTimeout(timeout); + return result; } start(id: number): Promise { return this._proxy.start(id); @@ -138,4 +147,51 @@ export class LocalPtyService extends Disposable implements IPtyService { getLatency(id: number): Promise { return this._proxy.getLatency(id); } + + async restartPtyHost(): Promise { + // TODO: Mark connection lost for all existing terminals on restart + this._disposePtyHost(); + [this._client, this._proxy] = this._startPtyHost(); + } + + private _disposePtyHost(): void { + if (this._proxy.shutdownAll) { + this._proxy.shutdownAll(); + } + this._client.dispose(); + } + + private _handleHeartbeat() { + this._clearHeartbeatTimeouts(); + this._heartbeatFirstTimeout = setTimeout(() => this._handleHeartbeatFirstTimeout(), HeartbeatConstants.BeatInterval * HeartbeatConstants.FirstWaitMultiplier); + } + + private _handleHeartbeatFirstTimeout() { + this._logService.warn(`No ptyHost heartbeat after ${HeartbeatConstants.BeatInterval * HeartbeatConstants.FirstWaitMultiplier}ms`); + this._heartbeatFirstTimeout = undefined; + this._heartbeatSecondTimeout = setTimeout(() => this._handleHeartbeatSecondTimeout(), HeartbeatConstants.BeatInterval * HeartbeatConstants.SecondWaitMultiplier); + } + + private _handleHeartbeatSecondTimeout() { + this._logService.error(`No ptyHost heartbeat after ${HeartbeatConstants.BeatInterval * HeartbeatConstants.FirstWaitMultiplier}ms!`); + this._heartbeatSecondTimeout = undefined; + this._onPtyHostUnresponsive.fire(); + } + + private _handleUnresponsiveCreateProcess() { + this._clearHeartbeatTimeouts(); + this._logService.error(`No ptyHost response to createProcess after ${HeartbeatConstants.CreateProcessTimeout}ms`); + this._onPtyHostUnresponsive.fire(); + } + + private _clearHeartbeatTimeouts() { + if (this._heartbeatFirstTimeout) { + clearTimeout(this._heartbeatFirstTimeout); + this._heartbeatFirstTimeout = undefined; + } + if (this._heartbeatSecondTimeout) { + clearTimeout(this._heartbeatSecondTimeout); + this._heartbeatSecondTimeout = undefined; + } + } } diff --git a/src/vs/platform/terminal/node/heartbeatService.ts b/src/vs/platform/terminal/node/heartbeatService.ts new file mode 100644 index 00000000000..3a414958afd --- /dev/null +++ b/src/vs/platform/terminal/node/heartbeatService.ts @@ -0,0 +1,22 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Emitter } from 'vs/base/common/event'; +import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; +import { HeartbeatConstants, IHeartbeatService } from 'vs/platform/terminal/common/terminal'; + +export class HeartbeatService extends Disposable implements IHeartbeatService { + private readonly _onBeat = this._register(new Emitter()); + readonly onBeat = this._onBeat.event; + + constructor() { + super(); + + const interval = setInterval(() => { + this._onBeat.fire(); + }, HeartbeatConstants.BeatInterval); + this._register(toDisposable(() => clearInterval(interval))); + } +} diff --git a/src/vs/platform/terminal/node/ptyHostMain.ts b/src/vs/platform/terminal/node/ptyHostMain.ts index 041e7d814c5..9515ddc130a 100644 --- a/src/vs/platform/terminal/node/ptyHostMain.ts +++ b/src/vs/platform/terminal/node/ptyHostMain.ts @@ -9,6 +9,7 @@ import { PtyService } from 'vs/platform/terminal/node/ptyService'; import { TerminalIpcChannels } from 'vs/platform/terminal/common/terminal'; import { ConsoleLogger, LogService } from 'vs/platform/log/common/log'; import { LogLevelChannel } from 'vs/platform/log/common/logIpc'; +import { HeartbeatService } from 'vs/platform/terminal/node/heartbeatService'; const server = new Server('ptyHost'); @@ -16,10 +17,14 @@ const logService = new LogService(new ConsoleLogger()); const logChannel = new LogLevelChannel(logService); server.registerChannel(TerminalIpcChannels.Log, logChannel); -const service = new PtyService(logService); -server.registerChannel(TerminalIpcChannels.PtyHost, ProxyChannel.fromService(service)); +const heartbeatService = new HeartbeatService(); +server.registerChannel(TerminalIpcChannels.Heartbeat, ProxyChannel.fromService(heartbeatService)); + +const ptyService = new PtyService(logService); +server.registerChannel(TerminalIpcChannels.PtyHost, ProxyChannel.fromService(ptyService)); process.once('exit', () => { logService.dispose(); - service.dispose(); + heartbeatService.dispose(); + ptyService.dispose(); }); diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index af4db72adb1..c68db027a57 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -17,6 +17,9 @@ export class PtyService extends Disposable implements IPtyService { private readonly _ptys: Map = new Map(); + private readonly _onHeartbeat = this._register(new Emitter()); + readonly onHeartbeat = this._onHeartbeat.event; + private readonly _onProcessData = this._register(new Emitter<{ id: number, event: IProcessDataEvent | string }>()); readonly onProcessData = this._onProcessData.event; private readonly _onProcessExit = this._register(new Emitter<{ id: number, event: number | undefined }>()); diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts index d30f3f0195c..ad42018a8f8 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts @@ -26,7 +26,8 @@ import { IShellLaunchConfig, ITerminalChildProcess } from 'vs/platform/terminal/ import { LocalPty } from 'vs/workbench/contrib/terminal/electron-sandbox/localPty'; import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; -import { INotificationService } from 'vs/platform/notification/common/notification'; +import { INotificationService, IPromptChoice, Severity } from 'vs/platform/notification/common/notification'; +import { localize } from 'vs/nls'; let Terminal: typeof XTermTerminal; let SearchAddon: typeof XTermSearchAddon; @@ -62,6 +63,15 @@ export class TerminalInstanceService extends Disposable implements ITerminalInst this._logService.info(`ptyHost restarted`); }); } + if (this._localPtyService.onPtyHostUnresponsive) { + this._localPtyService.onPtyHostUnresponsive(() => { + const choices: IPromptChoice[] = [{ + label: localize('restartPtyHost', "Restart pty host"), + run: () => this._localPtyService.restartPtyHost!() + }]; + notificationService.prompt(Severity.Error, localize('nonResponsivePtyHost', "The connection to the terminal's pty host process is unresponsive, the terminals may stop working."), choices); + }); + } } public async getXtermConstructor(): Promise { From b827a113d406cb07fd7173ce68738b9e747c6633 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 18 Feb 2021 07:52:51 -0800 Subject: [PATCH 316/325] Mark disconnected terminals and disable stdin --- src/vs/platform/terminal/common/terminal.ts | 2 +- .../platform/terminal/electron-browser/localPtyService.ts | 1 - src/vs/platform/terminal/node/ptyService.ts | 1 + src/vs/workbench/contrib/terminal/browser/terminal.ts | 5 +++++ .../workbench/contrib/terminal/browser/terminalInstance.ts | 4 ++++ .../contrib/terminal/browser/terminalInstanceService.ts | 6 ++++-- .../contrib/terminal/browser/terminalProcessManager.ts | 3 +++ src/vs/workbench/contrib/terminal/common/terminal.ts | 1 + .../terminal/electron-browser/terminalInstanceService.ts | 3 +++ 9 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index 2f223fe786a..a044f88525f 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -75,7 +75,7 @@ export enum HeartbeatConstants { /** * The duration between heartbeats */ - BeatInterval = 10000, + BeatInterval = 5000, /** * Defines a multiplier for BeatInterval for how long to wait before starting the second wait * timer. diff --git a/src/vs/platform/terminal/electron-browser/localPtyService.ts b/src/vs/platform/terminal/electron-browser/localPtyService.ts index 170058d1ab6..b7b9282058d 100644 --- a/src/vs/platform/terminal/electron-browser/localPtyService.ts +++ b/src/vs/platform/terminal/electron-browser/localPtyService.ts @@ -149,7 +149,6 @@ export class LocalPtyService extends Disposable implements IPtyService { } async restartPtyHost(): Promise { - // TODO: Mark connection lost for all existing terminals on restart this._disposePtyHost(); [this._client, this._proxy] = this._startPtyHost(); } diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index c68db027a57..1c260f3f56b 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -10,6 +10,7 @@ import { TerminalProcess } from 'vs/platform/terminal/node/terminalProcess'; import { Emitter } from 'vs/base/common/event'; import { ILogService } from 'vs/platform/log/common/log'; +// TODO: On disconnect/restart, this will overwrite the older terminals let currentPtyId = 0; export class PtyService extends Disposable implements IPtyService { diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index ccf2e8856a5..91f29c24520 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -30,6 +30,11 @@ export interface ITerminalInstanceService { /** Fired when the ptyHost process goes down, losing all connections to the service's ptys. */ onPtyHostExit: Event; + /** + * Fired when the ptyHost process becomes non-responsive, this should disable stdin for all + * terminals using this pty host connection and mark them as disconnected. + */ + onPtyHostUnresponsive: Event; // These events are optional as the requests they make are only needed on the browser side onRequestDefaultShellAndArgs?: Event; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 40c4a098459..52e391dc7dd 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -950,6 +950,10 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._processManager.onProcessOverrideDimensions(e => this.setDimensions(e, true)); this._processManager.onProcessResolvedShellLaunchConfig(e => this._setResolvedShellLaunchConfig(e)); this._processManager.onEnvironmentVariableInfoChanged(e => this._onEnvironmentVariableInfoChanged(e)); + this._processManager.onPtyDisconnect(() => { + this._safeSetOption('disableStdin', true); + this.setTitle(nls.localize('ptyDisconnected', "{0} (disconnected)", this._title), TitleEventSource.Process); + }); if (this._shellLaunchConfig.name) { this.setTitle(this._shellLaunchConfig.name, TitleEventSource.Api); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts index c9d2fa9512a..23020b11468 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts @@ -10,7 +10,7 @@ import type { SearchAddon as XTermSearchAddon } from 'xterm-addon-search'; import type { Unicode11Addon as XTermUnicode11Addon } from 'xterm-addon-unicode11'; import type { WebglAddon as XTermWebglAddon } from 'xterm-addon-webgl'; import { IProcessEnvironment } from 'vs/base/common/platform'; -import { Emitter, Event } from 'vs/base/common/event'; +import { Emitter } from 'vs/base/common/event'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ITerminalChildProcess } from 'vs/platform/terminal/common/terminal'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -25,8 +25,10 @@ export class TerminalInstanceService extends Disposable implements ITerminalInst private readonly _onPtyHostExit = this._register(new Emitter()); readonly onPtyHostExit = this._onPtyHostExit.event; + private readonly _onPtyHostUnresponsive = this._register(new Emitter()); + readonly onPtyHostUnresponsive = this._onPtyHostUnresponsive.event; private readonly _onRequestDefaultShellAndArgs = this._register(new Emitter()); - public get onRequestDefaultShellAndArgs(): Event { return this._onRequestDefaultShellAndArgs.event; } + readonly onRequestDefaultShellAndArgs = this._onRequestDefaultShellAndArgs.event; public async getXtermConstructor(): Promise { if (!Terminal) { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index 6176ce19267..beeb6039876 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -69,6 +69,8 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce private _ackDataBufferer: AckDataBufferer; private _hasWrittenData: boolean = false; + private readonly _onPtyDisconnect = this._register(new Emitter()); + public get onPtyDisconnect(): Event { return this._onPtyDisconnect.event; } private readonly _onProcessReady = this._register(new Emitter()); public get onProcessReady(): Event { return this._onProcessReady.event; } private readonly _onBeforeProcessData = this._register(new Emitter()); @@ -310,6 +312,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce const env = await this._setupEnvVariableInfo(activeWorkspaceRootUri, shellLaunchConfig); const useConpty = this._configHelper.config.windowsEnableConpty && !isScreenReaderModeEnabled; + this._terminalInstanceService.onPtyHostUnresponsive(() => this._onPtyDisconnect.fire()); return await this._terminalInstanceService.createTerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, useConpty); } diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 0b91bd1963b..7ad8acd2246 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -258,6 +258,7 @@ export interface ITerminalProcessManager extends IDisposable { /** Whether the process has had data written to it yet. */ readonly hasWrittenData: boolean; + readonly onPtyDisconnect: Event; readonly onProcessReady: Event; readonly onBeforeProcessData: Event; readonly onProcessData: Event; diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts index ad42018a8f8..ac7b80ade72 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts @@ -39,6 +39,8 @@ export class TerminalInstanceService extends Disposable implements ITerminalInst private readonly _onPtyHostExit = this._register(new Emitter()); readonly onPtyHostExit = this._onPtyHostExit.event; + private readonly _onPtyHostUnresponsive = this._register(new Emitter()); + readonly onPtyHostUnresponsive = this._onPtyHostUnresponsive.event; constructor( @IInstantiationService private readonly _instantiationService: IInstantiationService, @@ -70,6 +72,7 @@ export class TerminalInstanceService extends Disposable implements ITerminalInst run: () => this._localPtyService.restartPtyHost!() }]; notificationService.prompt(Severity.Error, localize('nonResponsivePtyHost', "The connection to the terminal's pty host process is unresponsive, the terminals may stop working."), choices); + this._onPtyHostUnresponsive.fire(); }); } } From 7d57388aebe2831c2c63bf642bd43fe1376d7ae1 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 18 Feb 2021 08:23:03 -0800 Subject: [PATCH 317/325] Tweak title source, create proc timeout --- src/vs/platform/terminal/common/terminal.ts | 2 +- src/vs/workbench/contrib/terminal/browser/terminalInstance.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index a044f88525f..3f54a3daf49 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -92,7 +92,7 @@ export enum HeartbeatConstants { * process. This short circuits the standard wait timeouts to tell the user sooner and only * create process is handled to avoid additional perf overhead. */ - CreateProcessTimeout = 3000 + CreateProcessTimeout = 2000 } export interface IHeartbeatService { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 52e391dc7dd..cbbab36147f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -952,7 +952,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._processManager.onEnvironmentVariableInfoChanged(e => this._onEnvironmentVariableInfoChanged(e)); this._processManager.onPtyDisconnect(() => { this._safeSetOption('disableStdin', true); - this.setTitle(nls.localize('ptyDisconnected', "{0} (disconnected)", this._title), TitleEventSource.Process); + // Use api source so it cannot be overridden + this.setTitle(nls.localize('ptyDisconnected', "{0} (disconnected)", this._title), TitleEventSource.Api); }); if (this._shellLaunchConfig.name) { From a246f643eeafc969d84276562d348ecd98369cb1 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 18 Feb 2021 17:26:07 +0100 Subject: [PATCH 318/325] debt, copy-paste police --- .../api/browser/mainThreadDocuments.ts | 7 ++- .../api/browser/mainThreadNotebook.ts | 52 +++---------------- 2 files changed, 9 insertions(+), 50 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadDocuments.ts b/src/vs/workbench/api/browser/mainThreadDocuments.ts index abdd99cd816..ca3afccd5e4 100644 --- a/src/vs/workbench/api/browser/mainThreadDocuments.ts +++ b/src/vs/workbench/api/browser/mainThreadDocuments.ts @@ -13,7 +13,6 @@ import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { IFileService, FileOperation } from 'vs/platform/files/common/files'; import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/browser/mainThreadDocumentsAndEditors'; import { ExtHostContext, ExtHostDocumentsShape, IExtHostContext, MainThreadDocumentsShape } from 'vs/workbench/api/common/extHost.protocol'; -import { ITextEditorModel } from 'vs/workbench/common/editor'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { toLocalResource, extUri, IExtUri } from 'vs/base/common/resources'; @@ -47,8 +46,8 @@ export class BoundModelReferenceCollection { } } - add(uri: URI, ref: IReference): void { - const length = ref.object.textEditorModel.getValueLength(); + add(uri: URI, ref: IReference, length: number = 0): void { + // const length = ref.object.textEditorModel.getValueLength(); let handle: any; let entry: { uri: URI, length: number, dispose(): void }; const dispose = () => { @@ -267,7 +266,7 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen private _handleAsResourceInput(uri: URI): Promise { return this._textModelResolverService.createModelReference(uri).then(ref => { - this._modelReferenceCollection.add(uri, ref); + this._modelReferenceCollection.add(uri, ref, ref.object.textEditorModel.getValueLength()); return ref.object.textEditorModel.uri; }); } diff --git a/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts index fe1b377f5e0..f53eda98d2b 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -7,23 +7,24 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { diffMaps, diffSets } from 'vs/base/common/collections'; import { Emitter } from 'vs/base/common/event'; import { IRelativePattern } from 'vs/base/common/glob'; -import { combinedDisposable, Disposable, DisposableStore, dispose, IDisposable, IReference } from 'vs/base/common/lifecycle'; +import { combinedDisposable, Disposable, DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle'; import { ResourceMap } from 'vs/base/common/map'; import { Schemas } from 'vs/base/common/network'; -import { IExtUri, isEqual } from 'vs/base/common/resources'; +import { isEqual } from 'vs/base/common/resources'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { EditorActivation, ITextEditorOptions } from 'vs/platform/editor/common/editor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; +import { BoundModelReferenceCollection } from 'vs/workbench/api/browser/mainThreadDocuments'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { viewColumnToEditorGroup } from 'vs/workbench/common/editor'; import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService'; -import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, DisplayOrderKey, ICellEditOperation, ICellRange, IEditor, IMainCellDto, INotebookDecorationRenderOptions, INotebookDocumentFilter, INotebookEditorModel, INotebookExclusiveDocumentFilter, INotebookKernel, NotebookCellsChangeType, NOTEBOOK_DISPLAY_ORDER, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, DisplayOrderKey, ICellEditOperation, ICellRange, IEditor, IMainCellDto, INotebookDecorationRenderOptions, INotebookDocumentFilter, INotebookExclusiveDocumentFilter, INotebookKernel, NotebookCellsChangeType, NOTEBOOK_DISPLAY_ORDER, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService'; import { IMainNotebookController, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IEditorGroup, IEditorGroupsService, preferredSideBySideGroupDirection } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -137,13 +138,14 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo super(); this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebook); this._modelReferenceCollection = new BoundModelReferenceCollection(this._uriIdentityService.extUri); - this._register(this._modelReferenceCollection); this.registerListeners(); } dispose(): void { super.dispose(); + this._modelReferenceCollection.dispose(); + // remove all notebook providers for (let item of this._notebookProviders.values()) { item.disposable.dispose(); @@ -715,45 +717,3 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo } } } - - -export class BoundModelReferenceCollection { - - private _data = new Array<{ uri: URI, dispose(): void }>(); - - constructor( - private readonly _extUri: IExtUri, - private readonly _maxAge: number = 1000 * 60 * 3, - ) { - // - } - - dispose(): void { - this._data = dispose(this._data); - } - - remove(uri: URI): void { - for (const entry of [...this._data] /* copy array because dispose will modify it */) { - if (this._extUri.isEqualOrParent(entry.uri, uri)) { - entry.dispose(); - } - } - } - - add(uri: URI, ref: IReference): void { - let handle: any; - let entry: { uri: URI, dispose(): void }; - const dispose = () => { - const idx = this._data.indexOf(entry); - if (idx >= 0) { - ref.dispose(); - clearTimeout(handle); - this._data.splice(idx, 1); - } - }; - handle = setTimeout(dispose, this._maxAge); - entry = { uri, dispose }; - - this._data.push(entry); - } -} From 2a12fd7202d3323327090e50b5521791ce2e13c0 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 18 Feb 2021 17:36:29 +0100 Subject: [PATCH 319/325] dispose more things, https://github.com/microsoft/vscode/issues/115698 --- .../workbench/api/browser/mainThreadNotebook.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts index f53eda98d2b..fd94f358f4e 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -111,16 +111,18 @@ class DocumentAndEditorState { @extHostNamedCustomer(MainContext.MainThreadNotebook) export class MainThreadNotebooks extends Disposable implements MainThreadNotebookShape { + + private readonly _proxy: ExtHostNotebookShape; private readonly _notebookProviders = new Map(); private readonly _notebookKernelProviders = new Map, provider: IDisposable }>(); - private readonly _proxy: ExtHostNotebookShape; private readonly _toDisposeOnEditorRemove = new Map(); - private _currentState?: DocumentAndEditorState; private readonly _editorEventListenersMapping: Map = new Map(); private readonly _documentEventListenersMapping: ResourceMap = new ResourceMap(); private readonly _cellStatusBarEntries: Map = new Map(); private readonly _modelReferenceCollection: BoundModelReferenceCollection; + private _currentState?: DocumentAndEditorState; + constructor( extHostContext: IExtHostContext, @IWorkingCopyService private readonly _workingCopyService: IWorkingCopyService, @@ -156,9 +158,10 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo item.emitter.dispose(); item.provider.dispose(); } - dispose(this._editorEventListenersMapping.values()); dispose(this._documentEventListenersMapping.values()); + dispose(this._toDisposeOnEditorRemove.values()); + dispose(this._cellStatusBarEntries.values()); } async $tryApplyEdits(_viewType: string, resource: UriComponents, modelVersionId: number, cellEdits: ICellEditOperation[]): Promise { @@ -459,7 +462,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo // if (!isEmptyChange) { this._currentState = newState; - await this._emitDelta(delta); + this._emitDelta(delta); // } } @@ -657,9 +660,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo } if (statusBarEntry.visible) { - this._cellStatusBarEntries.set( - id, - this._cellStatusBarService.addEntry(statusBarEntry)); + this._cellStatusBarEntries.set(id, this._cellStatusBarService.addEntry(statusBarEntry)); } } From 7effc11c7929651abccd011c671558758def857f Mon Sep 17 00:00:00 2001 From: Raymond Zhao Date: Thu, 18 Feb 2021 08:50:58 -0800 Subject: [PATCH 320/325] Bump Emmet version --- extensions/emmet/yarn.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/emmet/yarn.lock b/extensions/emmet/yarn.lock index e9ac076c3f0..117f331df39 100644 --- a/extensions/emmet/yarn.lock +++ b/extensions/emmet/yarn.lock @@ -54,9 +54,9 @@ integrity sha1-Rs/+oRmgoAMxKiHC2bVijLX81EI= "@types/node@^12.19.9": - version "12.20.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.0.tgz#692dfdecd6c97f5380c42dd50f19261f9f604deb" - integrity sha512-0/41wHcurotvSOTHQUFkgL702c3pyWR1mToSrrX3pGPvGfpHTv3Ksx0M4UVuU5VJfjVb62Eyr1eKO1tWNUCg2Q== + version "12.20.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.1.tgz#63d36c10e162666f0107f247cdca76542c3c7472" + integrity sha512-tCkE96/ZTO+cWbln2xfyvd6ngHLanvVlJ3e5BeirJ3BYI5GbAyubIrmV4JjjugDly5D9fHjOL5MNsqsCnqwW6g== emmet@^2.3.0: version "2.3.1" @@ -77,9 +77,9 @@ jsonc-parser@^2.3.0: integrity sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg== vscode-emmet-helper@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-2.3.0.tgz#a98357ad5ac9c71d7c00396f22b7963b1a74cc5c" - integrity sha512-QhU8+HlynMuUkqBYgA3wIDTSsUNkw8GWxLR214Hjvwr0lkFZa0CRqW/PzAI1CFREjSrTxJYQvkVnbfatZzKAuA== + version "2.3.1" + resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-2.3.1.tgz#f4f1d3b656441d96ded901536c014dcbf2419d9c" + integrity sha512-05zamij6z60pF6z4Dg6csbypc/Uxi9mBPzaPkfjOwdkn6+lYSrsiOME74MZLE4rhyWd46bvEtuGxAuR6gRKDpw== dependencies: emmet "^2.3.0" jsonc-parser "^2.3.0" From 2bb9fdfa8c26473c21abbfc93cd4861dc3423223 Mon Sep 17 00:00:00 2001 From: Hsuan-An Weng Lin Date: Thu, 18 Feb 2021 10:54:35 -0600 Subject: [PATCH 321/325] Emmet: add css.color.short setting (#116912) Fixes #72594 --- extensions/emmet/package.json | 5 +++++ extensions/emmet/package.nls.json | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/extensions/emmet/package.json b/extensions/emmet/package.json index 0766cda7bc4..5804c797484 100644 --- a/extensions/emmet/package.json +++ b/extensions/emmet/package.json @@ -217,6 +217,11 @@ "type": "boolean", "default": false, "description": "%emmetPreferencesOutputReverseAttributes%" + }, + "css.color.short": { + "type": "boolean", + "default": true, + "description": "%emmetPreferencesCssColorShort%" } } }, diff --git a/extensions/emmet/package.nls.json b/extensions/emmet/package.nls.json index 8e168ec4c4e..0c0d875d87c 100644 --- a/extensions/emmet/package.nls.json +++ b/extensions/emmet/package.nls.json @@ -56,5 +56,6 @@ "emmetPreferencesCssMsProperties": "Comma separated CSS properties that get the 'ms' vendor prefix when used in Emmet abbreviation that starts with `-`. Set to empty string to always avoid the 'ms' prefix.", "emmetPreferencesCssFuzzySearchMinScore": "The minimum score (from 0 to 1) that fuzzy-matched abbreviation should achieve. Lower values may produce many false-positive matches, higher values may reduce possible matches.", "emmetOptimizeStylesheetParsing": "When set to `false`, the whole file is parsed to determine if current position is valid for expanding Emmet abbreviations. When set to `true`, only the content around the current position in css/scss/less files is parsed.", - "emmetPreferencesOutputReverseAttributes": "If `true`, reverses attribute merging directions when resolving snippets." + "emmetPreferencesOutputReverseAttributes": "If `true`, reverses attribute merging directions when resolving snippets.", + "emmetPreferencesCssColorShort": "If `true`, color values like #f will be expanded to #fff instead of #ffffff." } From 63a9d5aa562458c065627b9a69c4cc7c78f3a91a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 18 Feb 2021 18:08:45 +0100 Subject: [PATCH 322/325] fix tests --- .../workbench/test/browser/api/mainThreadDocuments.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/test/browser/api/mainThreadDocuments.test.ts b/src/vs/workbench/test/browser/api/mainThreadDocuments.test.ts index 57be38dfd98..1c48801f6c5 100644 --- a/src/vs/workbench/test/browser/api/mainThreadDocuments.test.ts +++ b/src/vs/workbench/test/browser/api/mainThreadDocuments.test.ts @@ -46,7 +46,7 @@ suite('BoundModelReferenceCollection', () => { dispose() { disposed.push(0); } - }); + }, 6); col.add( URI.parse('test://boofar'), @@ -55,7 +55,7 @@ suite('BoundModelReferenceCollection', () => { dispose() { disposed.push(1); } - }); + }, 6); col.add( URI.parse('test://xxxxxxx'), @@ -64,7 +64,7 @@ suite('BoundModelReferenceCollection', () => { dispose() { disposed.push(2); } - }); + }, 70); assert.deepStrictEqual(disposed, [0, 1]); }); From 7bca8a91b4c43b9ed528157fcd95e1b97e681ff3 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 18 Feb 2021 18:09:28 +0100 Subject: [PATCH 323/325] send correct delta after restarting extension host, https://github.com/microsoft/vscode/issues/115698 --- .../api/browser/mainThreadNotebook.ts | 72 +++++++++---------- 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts index fd94f358f4e..566299adf3b 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -32,31 +32,20 @@ import { openEditorWith } from 'vs/workbench/services/editor/common/editorOpenWi import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; -import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, INotebookCellStatusBarEntryDto, INotebookDocumentsAndEditorsDelta, INotebookDocumentShowOptions, INotebookModelAddedData, MainContext, MainThreadNotebookShape, NotebookEditorRevealType, NotebookExtensionDescription } from '../common/extHost.protocol'; +import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, INotebookCellStatusBarEntryDto, INotebookDocumentsAndEditorsDelta, INotebookDocumentShowOptions, INotebookEditorAddData, INotebookModelAddedData, MainContext, MainThreadNotebookShape, NotebookEditorRevealType, NotebookExtensionDescription } from '../common/extHost.protocol'; class DocumentAndEditorState { static compute(before: DocumentAndEditorState | undefined, after: DocumentAndEditorState): INotebookDocumentsAndEditorsDelta { if (!before) { - const apiEditors = []; - for (let id in after.textEditors) { - const editor = after.textEditors.get(id)!; - apiEditors.push({ id, documentUri: editor.uri!, selections: editor!.getSelectionHandles(), visibleRanges: editor.visibleRanges }); - } - return { - addedDocuments: [], - addedEditors: apiEditors, + addedDocuments: [...after.documents].map(DocumentAndEditorState._asModelAddData), + addedEditors: [...after.textEditors.values()].map(DocumentAndEditorState._asEditorAddData), visibleEditors: [...after.visibleEditors].map(editor => editor[0]) }; } const documentDelta = diffSets(before.documents, after.documents); const editorDelta = diffMaps(before.textEditors, after.textEditors); - const addedAPIEditors = editorDelta.added.map(add => ({ - id: add.getId(), - documentUri: add.uri!, - selections: add.getSelectionHandles(), - visibleRanges: add.visibleRanges - })); + const addedAPIEditors = editorDelta.added.map(DocumentAndEditorState._asEditorAddData); const removedAPIEditors = editorDelta.removed.map(removed => removed.getId()); @@ -66,29 +55,7 @@ class DocumentAndEditorState { const visibleEditorDelta = diffMaps(before.visibleEditors, after.visibleEditors); return { - addedDocuments: documentDelta.added.map((e: NotebookTextModel): INotebookModelAddedData => { - return { - viewType: e.viewType, - uri: e.uri, - metadata: e.metadata, - versionId: e.versionId, - cells: e.cells.map(cell => ({ - handle: cell.handle, - uri: cell.uri, - source: cell.textBuffer.getLinesContent(), - eol: cell.textBuffer.getEOL(), - language: cell.language, - cellKind: cell.cellKind, - outputs: cell.outputs, - metadata: cell.metadata - })), - contentOptions: e.transientOptions, - // attachedEditor: editorId ? { - // id: editorId, - // selections: document.textModel.selections - // } : undefined - }; - }), + addedDocuments: documentDelta.added.map(DocumentAndEditorState._asModelAddData), removedDocuments: documentDelta.removed.map(e => e.uri), addedEditors: addedAPIEditors, removedEditors: removedAPIEditors, @@ -107,6 +74,35 @@ class DocumentAndEditorState { ) { // } + + private static _asModelAddData(e: NotebookTextModel): INotebookModelAddedData { + return { + viewType: e.viewType, + uri: e.uri, + metadata: e.metadata, + versionId: e.versionId, + cells: e.cells.map(cell => ({ + handle: cell.handle, + uri: cell.uri, + source: cell.textBuffer.getLinesContent(), + eol: cell.textBuffer.getEOL(), + language: cell.language, + cellKind: cell.cellKind, + outputs: cell.outputs, + metadata: cell.metadata + })), + contentOptions: e.transientOptions, + }; + } + + private static _asEditorAddData(add: IEditor): INotebookEditorAddData { + return { + id: add.getId(), + documentUri: add.uri!, + selections: add.getSelectionHandles(), + visibleRanges: add.visibleRanges + }; + } } @extHostNamedCustomer(MainContext.MainThreadNotebook) From 69d39a0ed3cff5aff319a8fefc4c25aa285f3aa0 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 18 Feb 2021 18:16:37 +0100 Subject: [PATCH 324/325] send event when removing a kernel, https://github.com/microsoft/vscode/issues/115698 --- src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts index 4c2d3e0c6ad..f0ae2a42917 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts @@ -723,6 +723,7 @@ export class NotebookService extends Disposable implements INotebookService, ICu return toDisposable(() => { kernelChangeEventListener.dispose(); d.dispose(); + this._onDidChangeKernels.fire(undefined); }); } From 6cc6794dbb6de570292f044069bcecc11014fa9d Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Thu, 18 Feb 2021 10:23:32 -0800 Subject: [PATCH 325/325] Support remote images --- .../contrib/welcome/gettingStarted/browser/gettingStarted.ts | 2 +- .../services/gettingStarted/common/gettingStartedService.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts index 45ea20fbcaf..482b3ca428a 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts @@ -257,7 +257,7 @@ export class GettingStartedPage extends EditorPane { private updateMediaSourceForColorMode(element: HTMLImageElement, sources: { hc: URI, dark: URI, light: URI }) { const themeType = this.themeService.getColorTheme().type; - element.src = sources[themeType].toString(); + element.src = sources[themeType].toString(true); } createEditor(parent: HTMLElement) { diff --git a/src/vs/workbench/services/gettingStarted/common/gettingStartedService.ts b/src/vs/workbench/services/gettingStarted/common/gettingStartedService.ts index d741ae8683a..8377ec8f9bf 100644 --- a/src/vs/workbench/services/gettingStarted/common/gettingStartedService.ts +++ b/src/vs/workbench/services/gettingStarted/common/gettingStartedService.ts @@ -18,6 +18,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { URI } from 'vs/base/common/uri'; import { joinPath } from 'vs/base/common/resources'; +import { FileAccess } from 'vs/base/common/network'; export const IGettingStartedService = createDecorator('gettingStartedService'); @@ -117,7 +118,7 @@ export class GettingStartedService extends Disposable implements IGettingStarted const convertPaths = (path: string | { hc: string, dark: string, light: string }): { hc: URI, dark: URI, light: URI } => { const convertPath = (path: string) => path.startsWith('https://') ? URI.parse(path, true) - : joinPath(extension.extensionLocation, path); + : FileAccess.asBrowserUri(joinPath(extension.extensionLocation, path)); if (typeof path === 'string') { const converted = convertPath(path);