diff --git a/.vscode/launch.json b/.vscode/launch.json index e6dc7eca9f..9b8f39afaf 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -69,10 +69,9 @@ } }, { - "type": "pwa-chrome", + "type": "chrome", "request": "attach", "name": "Attach to azuredatastudio", - "timeout": 50000, "port": 9222 }, { @@ -113,7 +112,7 @@ "preLaunchTask": "Ensure Prelaunch Dependencies", }, { - "type": "chrome", + "type": "node", "request": "launch", "name": "Launch ADS (Web) (TBD)", "program": "${workspaceFolder}/resources/web/code-web.js", diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index 0f89736c7a..3b186bb113 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -211,13 +211,6 @@ steps: zip -d $(agent.builddirectory)/VSCode-darwin.zip "*.pkg" displayName: Clean Archive -- script: | - set -e - AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ - node build/azure-pipelines/common/createAsset.js darwin-unnotarized archive "VSCode-darwin-$VSCODE_QUALITY.zip" $(agent.builddirectory)/VSCode-darwin.zip - displayName: Publish Unnotarized Build - - script: | APP_ROOT=$(agent.builddirectory)/VSCode-darwin APP_NAME="`ls $APP_ROOT | head -n 1`" diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index 42db14a31e..1f3a080508 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -6,7 +6,7 @@ schedules: displayName: Mon-Fri at 7:00 branches: include: - - main + - master resources: containers: diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index 0cdddf075d..5b63b4d283 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -26,7 +26,7 @@ "onCommand:markdown.showSource", "onCommand:markdown.showPreviewSecuritySelector", "onCommand:markdown.api.render", - "onCommand:notebook.showPreview", + "onCommand:notebook.showPreview", "onWebviewPanel:markdown.preview", "onCustomEditor:vscode.markdown.preview.editor" ], diff --git a/src/sql/base/browser/ui/selectBox/selectBox.ts b/src/sql/base/browser/ui/selectBox/selectBox.ts index 6e3e02ba0e..8631deb5b7 100644 --- a/src/sql/base/browser/ui/selectBox/selectBox.ts +++ b/src/sql/base/browser/ui/selectBox/selectBox.ts @@ -128,8 +128,8 @@ export class SelectBox extends vsSelectBox { private static createOptions(options: SelectOptionItemSQL[] | string[] | ISelectOptionItem[]): SelectOptionItemSQL[] { let selectOptions: SelectOptionItemSQL[]; - if (Array.isArray(options) && typeof (options[0]) === 'string') { - selectOptions = options.map(o => { + if (Array.isArray(options) && typeof (options[0]) === 'string') { + selectOptions = (options as string[]).map(o => { return { text: o, value: o } as SelectOptionItemSQL; }); } else { // Handle both SelectOptionItemSql and ISelectOptionItem diff --git a/src/sql/workbench/contrib/accounts/browser/accountManagement.contribution.ts b/src/sql/workbench/contrib/accounts/browser/accountManagement.contribution.ts index e0226fb89e..3e6d9dccd0 100644 --- a/src/sql/workbench/contrib/accounts/browser/accountManagement.contribution.ts +++ b/src/sql/workbench/contrib/accounts/browser/accountManagement.contribution.ts @@ -76,7 +76,7 @@ ExtensionsRegistry.registerExtensionPoint({ for (let extension of extensions) { const { value } = extension; - if (Array.isArray(value)) { + if (Array.isArray(value)) { for (let command of value) { handleCommand(command, extension); } diff --git a/src/sql/workbench/contrib/connection/common/connectionProviderExtension.ts b/src/sql/workbench/contrib/connection/common/connectionProviderExtension.ts index faaaf73a60..784130dae5 100644 --- a/src/sql/workbench/contrib/connection/common/connectionProviderExtension.ts +++ b/src/sql/workbench/contrib/connection/common/connectionProviderExtension.ts @@ -199,7 +199,7 @@ function resolveIconPath(extension: IExtensionPointUser): void { let baseDir = extension.description.extensionLocation.fsPath; let properties: ConnectionProviderProperties = extension.value; - if (Array.isArray(properties)) { + if (Array.isArray(properties)) { for (let p of properties) { toAbsolutePath(p['iconPath']); } diff --git a/src/sql/workbench/contrib/dashboard/browser/containers/dashboardContainer.contribution.ts b/src/sql/workbench/contrib/dashboard/browser/containers/dashboardContainer.contribution.ts index a9a6c5e3ad..4b0526de79 100644 --- a/src/sql/workbench/contrib/dashboard/browser/containers/dashboardContainer.contribution.ts +++ b/src/sql/workbench/contrib/dashboard/browser/containers/dashboardContainer.contribution.ts @@ -103,7 +103,7 @@ ExtensionsRegistry.registerExtensionPoint(value)) { + if (Array.isArray(value)) { for (const command of value) { handleCommand(command, extension); } diff --git a/src/sql/workbench/contrib/dashboard/browser/core/dashboardTab.contribution.ts b/src/sql/workbench/contrib/dashboard/browser/core/dashboardTab.contribution.ts index d9a4c306e1..d0a82f4aad 100644 --- a/src/sql/workbench/contrib/dashboard/browser/core/dashboardTab.contribution.ts +++ b/src/sql/workbench/contrib/dashboard/browser/core/dashboardTab.contribution.ts @@ -161,7 +161,7 @@ ExtensionsRegistry.registerExtensionPoint(value)) { + if (Array.isArray(value)) { for (const command of value) { handleTab(command, extension); } @@ -215,7 +215,7 @@ ExtensionsRegistry.registerExtensionPoint(value)) { + if (Array.isArray(value)) { for (const command of value) { handleTabGroup(command, extension); } diff --git a/src/sql/workbench/contrib/dashboard/browser/dashboardRegistry.ts b/src/sql/workbench/contrib/dashboard/browser/dashboardRegistry.ts index af477e3ab2..8c81535d95 100644 --- a/src/sql/workbench/contrib/dashboard/browser/dashboardRegistry.ts +++ b/src/sql/workbench/contrib/dashboard/browser/dashboardRegistry.ts @@ -298,7 +298,7 @@ ExtensionsRegistry.registerExtensionPoint(value)) { + if (Array.isArray(value)) { for (let command of value) { handleCommand(command, extension); } diff --git a/src/sql/workbench/contrib/dashboard/browser/widgets/insights/insightsWidget.contribution.ts b/src/sql/workbench/contrib/dashboard/browser/widgets/insights/insightsWidget.contribution.ts index 489d690697..505df1d937 100644 --- a/src/sql/workbench/contrib/dashboard/browser/widgets/insights/insightsWidget.contribution.ts +++ b/src/sql/workbench/contrib/dashboard/browser/widgets/insights/insightsWidget.contribution.ts @@ -37,7 +37,7 @@ ExtensionsRegistry.registerExtensionPoint(value)) { + if (Array.isArray(value)) { for (const command of value) { handleCommand(command, extension); } diff --git a/src/sql/workbench/services/notebook/browser/notebookServiceImpl.ts b/src/sql/workbench/services/notebook/browser/notebookServiceImpl.ts index f1e428b4ef..36c9d36015 100644 --- a/src/sql/workbench/services/notebook/browser/notebookServiceImpl.ts +++ b/src/sql/workbench/services/notebook/browser/notebookServiceImpl.ts @@ -191,7 +191,7 @@ export class NotebookService extends Disposable implements INotebookService { this._providers.set(p.id, new ProviderDescriptor()); } if (registration.fileExtensions) { - if (Array.isArray(registration.fileExtensions)) { + if (Array.isArray(registration.fileExtensions)) { for (let fileType of registration.fileExtensions) { this.addFileProvider(fileType, registration); } diff --git a/src/sql/workbench/services/notebook/common/notebookRegistry.ts b/src/sql/workbench/services/notebook/common/notebookRegistry.ts index e14faf6ba7..e3256e0a18 100644 --- a/src/sql/workbench/services/notebook/common/notebookRegistry.ts +++ b/src/sql/workbench/services/notebook/common/notebookRegistry.ts @@ -197,7 +197,7 @@ ExtensionsRegistry.registerExtensionPoint(value)) { + if (Array.isArray(value)) { for (let command of value) { handleExtension(command, extension); } @@ -215,7 +215,7 @@ ExtensionsRegistry.registerExtensionPoint(value)) { + if (Array.isArray(value)) { for (let command of value) { handleExtension(command, extension); } diff --git a/src/typings/lib.array-ext.d.ts b/src/typings/lib.array-ext.d.ts deleted file mode 100644 index 5b592172d7..0000000000 --- a/src/typings/lib.array-ext.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -interface ArrayConstructor { - isArray(arg: ReadonlyArray | null | undefined): arg is ReadonlyArray; - isArray(arg: Array | null | undefined): arg is Array; - isArray(arg: any): arg is Array; - isArray(arg: any): arg is Array; -} \ No newline at end of file diff --git a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts index 65770c5aba..6c48e65889 100644 --- a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts +++ b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts @@ -704,8 +704,8 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi let elementWidth = 0; if (container) { - let longest = -1; - let longestLength = -1; + let longest = 0; + let longestLength = 0; this.options.forEach((option, index) => { const len = option.text.length + (!!option.decoratorRight ? option.decoratorRight.length : 0); @@ -715,9 +715,8 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi } }); - if (longest >= 0) { - container.innerHTML = this.options[longest].text + (!!this.options[longest].decoratorRight ? (this.options[longest].decoratorRight + ' ') : ''); - } + + container.innerHTML = this.options[longest].text + (!!this.options[longest].decoratorRight ? (this.options[longest].decoratorRight + ' ') : ''); elementWidth = dom.getTotalWidth(container); } diff --git a/src/vs/base/browser/ui/tree/objectTreeModel.ts b/src/vs/base/browser/ui/tree/objectTreeModel.ts index 305fde3bc1..a3b48e8185 100644 --- a/src/vs/base/browser/ui/tree/objectTreeModel.ts +++ b/src/vs/base/browser/ui/tree/objectTreeModel.ts @@ -189,7 +189,7 @@ export class ObjectTreeModel, TFilterData extends Non let childrenNodes = [...node.children] as ITreeNode[]; if (recursive || first) { - childrenNodes = mergeSort(childrenNodes, this.sorter!.compare.bind(this.sorter)) as ITreeNode[]; + childrenNodes = mergeSort(childrenNodes, this.sorter!.compare.bind(this.sorter)) as ITreeNode[]; // {{SQL CARBON EDIT}} strict-null-checks } return Iterable.map, ITreeElement>(childrenNodes, node => ({ diff --git a/src/vs/base/common/uri.ts b/src/vs/base/common/uri.ts index 34aeec5345..f955f6f67b 100644 --- a/src/vs/base/common/uri.ts +++ b/src/vs/base/common/uri.ts @@ -383,7 +383,7 @@ export class URI implements UriComponents { static revive(data: UriComponents | URI | undefined | null): URI | undefined | null; static revive(data: UriComponents | URI | undefined | null): URI | undefined | null { if (!data) { - // {{SQL CARBON EDIT}} @todo chlafren change back to data when we enable strict null checks + // {{SQL CARBON EDIT}} strict-null-check return undefined; } else if (data instanceof URI) { return data; diff --git a/src/vs/base/parts/ipc/electron-main/ipc.electron-main.ts b/src/vs/base/parts/ipc/electron-main/ipc.electron-main.ts index 580b7d0993..0ebedc47bf 100644 --- a/src/vs/base/parts/ipc/electron-main/ipc.electron-main.ts +++ b/src/vs/base/parts/ipc/electron-main/ipc.electron-main.ts @@ -18,7 +18,7 @@ interface IIPCEvent { function createScopedOnMessageEvent(senderId: number, eventName: string): Event { const onMessage = Event.fromNodeEventEmitter(ipcMain, eventName, (event, message) => ({ event, message })); const onMessageFromSender = Event.filter(onMessage, ({ event }) => event.sender.id === senderId); - // {{SQL CARBON EDIT}} cast message as null since typescript isn't saying its always null + // {{SQL CARBON EDIT}} strict-null-checks return Event.map(onMessageFromSender, ({ message }) => message ? VSBuffer.wrap(message) : message as null); } diff --git a/src/vs/base/test/browser/ui/grid/grid.test.ts b/src/vs/base/test/browser/ui/grid/grid.test.ts new file mode 100644 index 0000000000..b589801a24 --- /dev/null +++ b/src/vs/base/test/browser/ui/grid/grid.test.ts @@ -0,0 +1,1080 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { Direction, getRelativeLocation, Orientation, SerializableGrid, ISerializableView, IViewDeserializer, GridNode, Sizing, isGridBranchNode, sanitizeGridNodeDescriptor, GridNodeDescriptor, createSerializedGrid, Grid } from 'vs/base/browser/ui/grid/grid'; +import { TestView, nodesToArrays } from './util'; +import { deepClone } from 'vs/base/common/objects'; +import { Event } from 'vs/base/common/event'; + +// Simple example: +// +// +-----+---------------+ +// | 4 | 2 | +// +-----+---------+-----+ +// | 1 | | +// +---------------+ 3 | +// | 5 | | +// +---------------+-----+ +// +// V +// +-H +// | +-4 +// | +-2 +// +-H +// +-V +// | +-1 +// | +-5 +// +-3 + +suite('Grid', function () { + let container: HTMLElement; + + setup(function () { + container = document.createElement('div'); + container.style.position = 'absolute'; + container.style.width = `${800}px`; + container.style.height = `${600}px`; + }); + + test('getRelativeLocation', () => { + assert.deepEqual(getRelativeLocation(Orientation.VERTICAL, [0], Direction.Up), [0]); + assert.deepEqual(getRelativeLocation(Orientation.VERTICAL, [0], Direction.Down), [1]); + assert.deepEqual(getRelativeLocation(Orientation.VERTICAL, [0], Direction.Left), [0, 0]); + assert.deepEqual(getRelativeLocation(Orientation.VERTICAL, [0], Direction.Right), [0, 1]); + + assert.deepEqual(getRelativeLocation(Orientation.HORIZONTAL, [0], Direction.Up), [0, 0]); + assert.deepEqual(getRelativeLocation(Orientation.HORIZONTAL, [0], Direction.Down), [0, 1]); + assert.deepEqual(getRelativeLocation(Orientation.HORIZONTAL, [0], Direction.Left), [0]); + assert.deepEqual(getRelativeLocation(Orientation.HORIZONTAL, [0], Direction.Right), [1]); + + assert.deepEqual(getRelativeLocation(Orientation.VERTICAL, [4], Direction.Up), [4]); + assert.deepEqual(getRelativeLocation(Orientation.VERTICAL, [4], Direction.Down), [5]); + assert.deepEqual(getRelativeLocation(Orientation.VERTICAL, [4], Direction.Left), [4, 0]); + assert.deepEqual(getRelativeLocation(Orientation.VERTICAL, [4], Direction.Right), [4, 1]); + + assert.deepEqual(getRelativeLocation(Orientation.VERTICAL, [0, 0], Direction.Up), [0, 0, 0]); + assert.deepEqual(getRelativeLocation(Orientation.VERTICAL, [0, 0], Direction.Down), [0, 0, 1]); + assert.deepEqual(getRelativeLocation(Orientation.VERTICAL, [0, 0], Direction.Left), [0, 0]); + assert.deepEqual(getRelativeLocation(Orientation.VERTICAL, [0, 0], Direction.Right), [0, 1]); + + assert.deepEqual(getRelativeLocation(Orientation.VERTICAL, [1, 2], Direction.Up), [1, 2, 0]); + assert.deepEqual(getRelativeLocation(Orientation.VERTICAL, [1, 2], Direction.Down), [1, 2, 1]); + assert.deepEqual(getRelativeLocation(Orientation.VERTICAL, [1, 2], Direction.Left), [1, 2]); + assert.deepEqual(getRelativeLocation(Orientation.VERTICAL, [1, 2], Direction.Right), [1, 3]); + + assert.deepEqual(getRelativeLocation(Orientation.VERTICAL, [1, 2, 3], Direction.Up), [1, 2, 3]); + assert.deepEqual(getRelativeLocation(Orientation.VERTICAL, [1, 2, 3], Direction.Down), [1, 2, 4]); + assert.deepEqual(getRelativeLocation(Orientation.VERTICAL, [1, 2, 3], Direction.Left), [1, 2, 3, 0]); + assert.deepEqual(getRelativeLocation(Orientation.VERTICAL, [1, 2, 3], Direction.Right), [1, 2, 3, 1]); + }); + + test('empty', () => { + const view1 = new TestView(100, Number.MAX_VALUE, 100, Number.MAX_VALUE); + const gridview = new Grid(view1); + container.appendChild(gridview.element); + gridview.layout(800, 600); + + assert.deepEqual(view1.size, [800, 600]); + }); + + test('two views vertically', function () { + const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new Grid(view1); + container.appendChild(grid.element); + grid.layout(800, 600); + assert.deepEqual(view1.size, [800, 600]); + + const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, 200, view1, Direction.Up); + assert.deepEqual(view1.size, [800, 400]); + assert.deepEqual(view2.size, [800, 200]); + }); + + test('two views horizontally', function () { + const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new Grid(view1); + container.appendChild(grid.element); + + grid.layout(800, 600); + assert.deepEqual(view1.size, [800, 600]); + + const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, 300, view1, Direction.Right); + assert.deepEqual(view1.size, [500, 600]); + assert.deepEqual(view2.size, [300, 600]); + }); + + test('simple layout', function () { + const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new Grid(view1); + container.appendChild(grid.element); + + grid.layout(800, 600); + assert.deepEqual(view1.size, [800, 600]); + + const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, 200, view1, Direction.Up); + assert.deepEqual(view1.size, [800, 400]); + assert.deepEqual(view2.size, [800, 200]); + + const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, 200, view1, Direction.Right); + assert.deepEqual(view1.size, [600, 400]); + assert.deepEqual(view2.size, [800, 200]); + assert.deepEqual(view3.size, [200, 400]); + + const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view4, 200, view2, Direction.Left); + assert.deepEqual(view1.size, [600, 400]); + assert.deepEqual(view2.size, [600, 200]); + assert.deepEqual(view3.size, [200, 400]); + assert.deepEqual(view4.size, [200, 200]); + + const view5 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view5, 100, view1, Direction.Down); + assert.deepEqual(view1.size, [600, 300]); + assert.deepEqual(view2.size, [600, 200]); + assert.deepEqual(view3.size, [200, 400]); + assert.deepEqual(view4.size, [200, 200]); + assert.deepEqual(view5.size, [600, 100]); + }); + + test('another simple layout with automatic size distribution', function () { + const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new Grid(view1); + container.appendChild(grid.element); + + grid.layout(800, 600); + assert.deepEqual(view1.size, [800, 600]); + + const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, Sizing.Distribute, view1, Direction.Left); + assert.deepEqual(view1.size, [400, 600]); + assert.deepEqual(view2.size, [400, 600]); + + const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, Sizing.Distribute, view1, Direction.Right); + assert.deepEqual(view1.size, [266, 600]); + assert.deepEqual(view2.size, [266, 600]); + assert.deepEqual(view3.size, [268, 600]); + + const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view4, Sizing.Distribute, view2, Direction.Down); + assert.deepEqual(view1.size, [266, 600]); + assert.deepEqual(view2.size, [266, 300]); + assert.deepEqual(view3.size, [268, 600]); + assert.deepEqual(view4.size, [266, 300]); + + const view5 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view5, Sizing.Distribute, view3, Direction.Up); + assert.deepEqual(view1.size, [266, 600]); + assert.deepEqual(view2.size, [266, 300]); + assert.deepEqual(view3.size, [268, 300]); + assert.deepEqual(view4.size, [266, 300]); + assert.deepEqual(view5.size, [268, 300]); + + const view6 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view6, Sizing.Distribute, view3, Direction.Down); + assert.deepEqual(view1.size, [266, 600]); + assert.deepEqual(view2.size, [266, 300]); + assert.deepEqual(view3.size, [268, 200]); + assert.deepEqual(view4.size, [266, 300]); + assert.deepEqual(view5.size, [268, 200]); + assert.deepEqual(view6.size, [268, 200]); + }); + + test('another simple layout with split size distribution', function () { + const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new Grid(view1); + container.appendChild(grid.element); + + grid.layout(800, 600); + assert.deepEqual(view1.size, [800, 600]); + + const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, Sizing.Split, view1, Direction.Left); + assert.deepEqual(view1.size, [400, 600]); + assert.deepEqual(view2.size, [400, 600]); + + const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, Sizing.Split, view1, Direction.Right); + assert.deepEqual(view1.size, [200, 600]); + assert.deepEqual(view2.size, [400, 600]); + assert.deepEqual(view3.size, [200, 600]); + + const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view4, Sizing.Split, view2, Direction.Down); + assert.deepEqual(view1.size, [200, 600]); + assert.deepEqual(view2.size, [400, 300]); + assert.deepEqual(view3.size, [200, 600]); + assert.deepEqual(view4.size, [400, 300]); + + const view5 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view5, Sizing.Split, view3, Direction.Up); + assert.deepEqual(view1.size, [200, 600]); + assert.deepEqual(view2.size, [400, 300]); + assert.deepEqual(view3.size, [200, 300]); + assert.deepEqual(view4.size, [400, 300]); + assert.deepEqual(view5.size, [200, 300]); + + const view6 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view6, Sizing.Split, view3, Direction.Down); + assert.deepEqual(view1.size, [200, 600]); + assert.deepEqual(view2.size, [400, 300]); + assert.deepEqual(view3.size, [200, 150]); + assert.deepEqual(view4.size, [400, 300]); + assert.deepEqual(view5.size, [200, 300]); + assert.deepEqual(view6.size, [200, 150]); + }); + + test('3/2 layout with split', function () { + const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new Grid(view1); + container.appendChild(grid.element); + + grid.layout(800, 600); + assert.deepEqual(view1.size, [800, 600]); + + const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, Sizing.Split, view1, Direction.Down); + assert.deepEqual(view1.size, [800, 300]); + assert.deepEqual(view2.size, [800, 300]); + + const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, Sizing.Split, view2, Direction.Right); + assert.deepEqual(view1.size, [800, 300]); + assert.deepEqual(view2.size, [400, 300]); + assert.deepEqual(view3.size, [400, 300]); + + const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view4, Sizing.Split, view1, Direction.Right); + assert.deepEqual(view1.size, [400, 300]); + assert.deepEqual(view2.size, [400, 300]); + assert.deepEqual(view3.size, [400, 300]); + assert.deepEqual(view4.size, [400, 300]); + + const view5 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view5, Sizing.Split, view1, Direction.Right); + assert.deepEqual(view1.size, [200, 300]); + assert.deepEqual(view2.size, [400, 300]); + assert.deepEqual(view3.size, [400, 300]); + assert.deepEqual(view4.size, [400, 300]); + assert.deepEqual(view5.size, [200, 300]); + }); + + test('sizing should be correct after branch demotion #50564', function () { + const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new Grid(view1); + container.appendChild(grid.element); + + grid.layout(800, 600); + + const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, Sizing.Split, view1, Direction.Right); + + const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, Sizing.Split, view2, Direction.Down); + + const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view4, Sizing.Split, view2, Direction.Right); + assert.deepEqual(view1.size, [400, 600]); + assert.deepEqual(view2.size, [200, 300]); + assert.deepEqual(view3.size, [400, 300]); + assert.deepEqual(view4.size, [200, 300]); + + grid.removeView(view3); + assert.deepEqual(view1.size, [400, 600]); + assert.deepEqual(view2.size, [200, 600]); + assert.deepEqual(view4.size, [200, 600]); + }); + + test('sizing should be correct after branch demotion #50675', function () { + const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new Grid(view1); + container.appendChild(grid.element); + + grid.layout(800, 600); + + const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, Sizing.Distribute, view1, Direction.Down); + + const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, Sizing.Distribute, view2, Direction.Down); + + const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view4, Sizing.Distribute, view3, Direction.Right); + assert.deepEqual(view1.size, [800, 200]); + assert.deepEqual(view2.size, [800, 200]); + assert.deepEqual(view3.size, [400, 200]); + assert.deepEqual(view4.size, [400, 200]); + + grid.removeView(view3, Sizing.Distribute); + assert.deepEqual(view1.size, [800, 200]); + assert.deepEqual(view2.size, [800, 200]); + assert.deepEqual(view4.size, [800, 200]); + }); + + test('getNeighborViews should work on single view layout', function () { + const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new Grid(view1); + container.appendChild(grid.element); + + grid.layout(800, 600); + + assert.deepEqual(grid.getNeighborViews(view1, Direction.Up), []); + assert.deepEqual(grid.getNeighborViews(view1, Direction.Right), []); + assert.deepEqual(grid.getNeighborViews(view1, Direction.Down), []); + assert.deepEqual(grid.getNeighborViews(view1, Direction.Left), []); + + assert.deepEqual(grid.getNeighborViews(view1, Direction.Up, true), [view1]); + assert.deepEqual(grid.getNeighborViews(view1, Direction.Right, true), [view1]); + assert.deepEqual(grid.getNeighborViews(view1, Direction.Down, true), [view1]); + assert.deepEqual(grid.getNeighborViews(view1, Direction.Left, true), [view1]); + }); + + test('getNeighborViews should work on simple layout', function () { + const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new Grid(view1); + container.appendChild(grid.element); + + grid.layout(800, 600); + + const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, Sizing.Distribute, view1, Direction.Down); + + const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, Sizing.Distribute, view2, Direction.Down); + + assert.deepEqual(grid.getNeighborViews(view1, Direction.Up), []); + assert.deepEqual(grid.getNeighborViews(view1, Direction.Right), []); + assert.deepEqual(grid.getNeighborViews(view1, Direction.Down), [view2]); + assert.deepEqual(grid.getNeighborViews(view1, Direction.Left), []); + + assert.deepEqual(grid.getNeighborViews(view1, Direction.Up, true), [view3]); + assert.deepEqual(grid.getNeighborViews(view1, Direction.Right, true), [view1]); + assert.deepEqual(grid.getNeighborViews(view1, Direction.Down, true), [view2]); + assert.deepEqual(grid.getNeighborViews(view1, Direction.Left, true), [view1]); + + assert.deepEqual(grid.getNeighborViews(view2, Direction.Up), [view1]); + assert.deepEqual(grid.getNeighborViews(view2, Direction.Right), []); + assert.deepEqual(grid.getNeighborViews(view2, Direction.Down), [view3]); + assert.deepEqual(grid.getNeighborViews(view2, Direction.Left), []); + + assert.deepEqual(grid.getNeighborViews(view2, Direction.Up, true), [view1]); + assert.deepEqual(grid.getNeighborViews(view2, Direction.Right, true), [view2]); + assert.deepEqual(grid.getNeighborViews(view2, Direction.Down, true), [view3]); + assert.deepEqual(grid.getNeighborViews(view2, Direction.Left, true), [view2]); + + assert.deepEqual(grid.getNeighborViews(view3, Direction.Up), [view2]); + assert.deepEqual(grid.getNeighborViews(view3, Direction.Right), []); + assert.deepEqual(grid.getNeighborViews(view3, Direction.Down), []); + assert.deepEqual(grid.getNeighborViews(view3, Direction.Left), []); + + assert.deepEqual(grid.getNeighborViews(view3, Direction.Up, true), [view2]); + assert.deepEqual(grid.getNeighborViews(view3, Direction.Right, true), [view3]); + assert.deepEqual(grid.getNeighborViews(view3, Direction.Down, true), [view1]); + assert.deepEqual(grid.getNeighborViews(view3, Direction.Left, true), [view3]); + }); + + test('getNeighborViews should work on a complex layout', function () { + const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new Grid(view1); + container.appendChild(grid.element); + + grid.layout(800, 600); + + const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, Sizing.Distribute, view1, Direction.Down); + + const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, Sizing.Distribute, view2, Direction.Down); + + const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view4, Sizing.Distribute, view2, Direction.Right); + + const view5 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view5, Sizing.Distribute, view4, Direction.Down); + + assert.deepEqual(grid.getNeighborViews(view1, Direction.Up), []); + assert.deepEqual(grid.getNeighborViews(view1, Direction.Right), []); + assert.deepEqual(grid.getNeighborViews(view1, Direction.Down), [view2, view4]); + assert.deepEqual(grid.getNeighborViews(view1, Direction.Left), []); + assert.deepEqual(grid.getNeighborViews(view2, Direction.Up), [view1]); + assert.deepEqual(grid.getNeighborViews(view2, Direction.Right), [view4, view5]); + assert.deepEqual(grid.getNeighborViews(view2, Direction.Down), [view3]); + assert.deepEqual(grid.getNeighborViews(view2, Direction.Left), []); + assert.deepEqual(grid.getNeighborViews(view4, Direction.Up), [view1]); + assert.deepEqual(grid.getNeighborViews(view4, Direction.Right), []); + assert.deepEqual(grid.getNeighborViews(view4, Direction.Down), [view5]); + assert.deepEqual(grid.getNeighborViews(view4, Direction.Left), [view2]); + assert.deepEqual(grid.getNeighborViews(view5, Direction.Up), [view4]); + assert.deepEqual(grid.getNeighborViews(view5, Direction.Right), []); + assert.deepEqual(grid.getNeighborViews(view5, Direction.Down), [view3]); + assert.deepEqual(grid.getNeighborViews(view5, Direction.Left), [view2]); + assert.deepEqual(grid.getNeighborViews(view3, Direction.Up), [view2, view5]); + assert.deepEqual(grid.getNeighborViews(view3, Direction.Right), []); + assert.deepEqual(grid.getNeighborViews(view3, Direction.Down), []); + assert.deepEqual(grid.getNeighborViews(view3, Direction.Left), []); + }); + + test('getNeighborViews should work on another simple layout', function () { + const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new Grid(view1); + container.appendChild(grid.element); + + grid.layout(800, 600); + + const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, Sizing.Distribute, view1, Direction.Right); + + const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, Sizing.Distribute, view2, Direction.Down); + + const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view4, Sizing.Distribute, view2, Direction.Right); + + assert.deepEqual(grid.getNeighborViews(view4, Direction.Up), []); + assert.deepEqual(grid.getNeighborViews(view4, Direction.Right), []); + assert.deepEqual(grid.getNeighborViews(view4, Direction.Down), [view3]); + assert.deepEqual(grid.getNeighborViews(view4, Direction.Left), [view2]); + }); + + test('getNeighborViews should only return immediate neighbors', function () { + const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new Grid(view1); + container.appendChild(grid.element); + + grid.layout(800, 600); + + const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, Sizing.Distribute, view1, Direction.Right); + + const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, Sizing.Distribute, view2, Direction.Down); + + const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view4, Sizing.Distribute, view2, Direction.Right); + + assert.deepEqual(grid.getNeighborViews(view1, Direction.Right), [view2, view3]); + }); +}); + +class TestSerializableView extends TestView implements ISerializableView { + + constructor( + readonly name: string, + minimumWidth: number, + maximumWidth: number, + minimumHeight: number, + maximumHeight: number + ) { + super(minimumWidth, maximumWidth, minimumHeight, maximumHeight); + } + + toJSON() { + return { name: this.name }; + } +} + +class TestViewDeserializer implements IViewDeserializer { + + private views = new Map(); + + fromJSON(json: any): TestSerializableView { + const view = new TestSerializableView(json.name, 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + this.views.set(json.name, view); + return view; + } + + getView(id: string): TestSerializableView { + const view = this.views.get(id); + if (!view) { + throw new Error('Unknown view'); + } + return view; + } +} + +function nodesToNames(node: GridNode): any { + if (isGridBranchNode(node)) { + return node.children.map(nodesToNames); + } else { + return node.view.name; + } +} + +suite('SerializableGrid', function () { + + let container: HTMLElement; + + setup(function () { + container = document.createElement('div'); + container.style.position = 'absolute'; + container.style.width = `${800}px`; + container.style.height = `${600}px`; + }); + + test('serialize empty', function () { + const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new SerializableGrid(view1); + container.appendChild(grid.element); + grid.layout(800, 600); + + const actual = grid.serialize(); + assert.deepEqual(actual, { + orientation: 0, + width: 800, + height: 600, + root: { + type: 'branch', + data: [ + { + type: 'leaf', + data: { + name: 'view1', + }, + size: 600 + } + ], + size: 800 + } + }); + }); + + test('serialize simple layout', function () { + const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new SerializableGrid(view1); + container.appendChild(grid.element); + grid.layout(800, 600); + + const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, 200, view1, Direction.Up); + + const view3 = new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, 200, view1, Direction.Right); + + const view4 = new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view4, 200, view2, Direction.Left); + + const view5 = new TestSerializableView('view5', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view5, 100, view1, Direction.Down); + + assert.deepEqual(grid.serialize(), { + orientation: 0, + width: 800, + height: 600, + root: { + type: 'branch', + data: [ + { + type: 'branch', + data: [ + { type: 'leaf', data: { name: 'view4' }, size: 200 }, + { type: 'leaf', data: { name: 'view2' }, size: 600 } + ], + size: 200 + }, + { + type: 'branch', + data: [ + { + type: 'branch', + data: [ + { type: 'leaf', data: { name: 'view1' }, size: 300 }, + { type: 'leaf', data: { name: 'view5' }, size: 100 } + ], + size: 600 + }, + { type: 'leaf', data: { name: 'view3' }, size: 200 } + ], + size: 400 + } + ], + size: 800 + } + }); + }); + + test('deserialize empty', function () { + const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new SerializableGrid(view1); + container.appendChild(grid.element); + grid.layout(800, 600); + + const json = grid.serialize(); + grid.dispose(); + + const deserializer = new TestViewDeserializer(); + const grid2 = SerializableGrid.deserialize(json, deserializer); + grid2.layout(800, 600); + + assert.deepEqual(nodesToNames(grid2.getViews()), ['view1']); + }); + + test('deserialize simple layout', function () { + const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new SerializableGrid(view1); + container.appendChild(grid.element); + + grid.layout(800, 600); + + const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, 200, view1, Direction.Up); + + const view3 = new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, 200, view1, Direction.Right); + + const view4 = new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view4, 200, view2, Direction.Left); + + const view5 = new TestSerializableView('view5', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view5, 100, view1, Direction.Down); + + const json = grid.serialize(); + grid.dispose(); + + const deserializer = new TestViewDeserializer(); + const grid2 = SerializableGrid.deserialize(json, deserializer); + + const view1Copy = deserializer.getView('view1'); + const view2Copy = deserializer.getView('view2'); + const view3Copy = deserializer.getView('view3'); + const view4Copy = deserializer.getView('view4'); + const view5Copy = deserializer.getView('view5'); + + assert.deepEqual(nodesToArrays(grid2.getViews()), [[view4Copy, view2Copy], [[view1Copy, view5Copy], view3Copy]]); + + grid2.layout(800, 600); + + assert.deepEqual(view1Copy.size, [600, 300]); + assert.deepEqual(view2Copy.size, [600, 200]); + assert.deepEqual(view3Copy.size, [200, 400]); + assert.deepEqual(view4Copy.size, [200, 200]); + assert.deepEqual(view5Copy.size, [600, 100]); + }); + + test('deserialize simple layout with scaling', function () { + const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new SerializableGrid(view1); + container.appendChild(grid.element); + + grid.layout(800, 600); + + const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, 200, view1, Direction.Up); + + const view3 = new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, 200, view1, Direction.Right); + + const view4 = new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view4, 200, view2, Direction.Left); + + const view5 = new TestSerializableView('view5', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view5, 100, view1, Direction.Down); + + const json = grid.serialize(); + grid.dispose(); + + const deserializer = new TestViewDeserializer(); + const grid2 = SerializableGrid.deserialize(json, deserializer); + + const view1Copy = deserializer.getView('view1'); + const view2Copy = deserializer.getView('view2'); + const view3Copy = deserializer.getView('view3'); + const view4Copy = deserializer.getView('view4'); + const view5Copy = deserializer.getView('view5'); + + grid2.layout(400, 800); // [/2, *4/3] + assert.deepEqual(view1Copy.size, [300, 400]); + assert.deepEqual(view2Copy.size, [300, 267]); + assert.deepEqual(view3Copy.size, [100, 533]); + assert.deepEqual(view4Copy.size, [100, 267]); + assert.deepEqual(view5Copy.size, [300, 133]); + }); + + test('deserialize 4 view layout (ben issue #2)', function () { + const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new SerializableGrid(view1); + container.appendChild(grid.element); + grid.layout(800, 600); + + const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, Sizing.Split, view1, Direction.Down); + + const view3 = new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, Sizing.Split, view2, Direction.Down); + + const view4 = new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view4, Sizing.Split, view3, Direction.Right); + + const json = grid.serialize(); + grid.dispose(); + + const deserializer = new TestViewDeserializer(); + const grid2 = SerializableGrid.deserialize(json, deserializer); + + const view1Copy = deserializer.getView('view1'); + const view2Copy = deserializer.getView('view2'); + const view3Copy = deserializer.getView('view3'); + const view4Copy = deserializer.getView('view4'); + + grid2.layout(800, 600); + + assert.deepEqual(view1Copy.size, [800, 300]); + assert.deepEqual(view2Copy.size, [800, 150]); + assert.deepEqual(view3Copy.size, [400, 150]); + assert.deepEqual(view4Copy.size, [400, 150]); + }); + + test('deserialize 2 view layout (ben issue #3)', function () { + const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new SerializableGrid(view1); + container.appendChild(grid.element); + + grid.layout(800, 600); + + const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, Sizing.Split, view1, Direction.Right); + + const json = grid.serialize(); + grid.dispose(); + + const deserializer = new TestViewDeserializer(); + const grid2 = SerializableGrid.deserialize(json, deserializer); + + const view1Copy = deserializer.getView('view1'); + const view2Copy = deserializer.getView('view2'); + + grid2.layout(800, 600); + + assert.deepEqual(view1Copy.size, [400, 600]); + assert.deepEqual(view2Copy.size, [400, 600]); + }); + + test('deserialize simple view layout #50609', function () { + const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new SerializableGrid(view1); + container.appendChild(grid.element); + + grid.layout(800, 600); + + const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, Sizing.Split, view1, Direction.Right); + + const view3 = new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, Sizing.Split, view2, Direction.Down); + + grid.removeView(view1, Sizing.Split); + + const json = grid.serialize(); + grid.dispose(); + + const deserializer = new TestViewDeserializer(); + const grid2 = SerializableGrid.deserialize(json, deserializer); + + const view2Copy = deserializer.getView('view2'); + const view3Copy = deserializer.getView('view3'); + + grid2.layout(800, 600); + + assert.deepEqual(view2Copy.size, [800, 300]); + assert.deepEqual(view3Copy.size, [800, 300]); + }); + + test('sanitizeGridNodeDescriptor', () => { + const nodeDescriptor = { groups: [{ size: 0.2 }, { size: 0.2 }, { size: 0.6, groups: [{}, {}] }] }; + const nodeDescriptorCopy = deepClone(nodeDescriptor); + sanitizeGridNodeDescriptor(nodeDescriptorCopy, true); + assert.deepEqual(nodeDescriptorCopy, { groups: [{ size: 0.2 }, { size: 0.2 }, { size: 0.6, groups: [{ size: 0.5 }, { size: 0.5 }] }] }); + }); + + test('createSerializedGrid', () => { + const gridDescriptor = { orientation: Orientation.VERTICAL, groups: [{ size: 0.2 }, { size: 0.2 }, { size: 0.6, groups: [{}, {}] }] }; + const serializedGrid = createSerializedGrid(gridDescriptor); + assert.deepEqual(serializedGrid, { + root: { + type: 'branch', + size: undefined, + data: [ + { type: 'leaf', size: 0.2, data: null }, + { type: 'leaf', size: 0.2, data: null }, + { + type: 'branch', size: 0.6, data: [ + { type: 'leaf', size: 0.5, data: null }, + { type: 'leaf', size: 0.5, data: null } + ] + } + ] + }, + orientation: Orientation.VERTICAL, + width: 1, + height: 1 + }); + }); + + test('createSerializedGrid - issue #85601, should not allow single children groups', () => { + const serializedGrid = createSerializedGrid({ orientation: Orientation.HORIZONTAL, groups: [{ groups: [{}, {}], size: 0.5 }, { groups: [{}], size: 0.5 }] }); + const views: ISerializableView[] = []; + const deserializer = new class implements IViewDeserializer { + fromJSON(): ISerializableView { + const view: ISerializableView = { + element: document.createElement('div'), + layout: () => null, + minimumWidth: 0, + maximumWidth: Number.POSITIVE_INFINITY, + minimumHeight: 0, + maximumHeight: Number.POSITIVE_INFINITY, + onDidChange: Event.None, + toJSON: () => ({}) + }; + views.push(view); + return view; + } + }; + + const grid = SerializableGrid.deserialize(serializedGrid, deserializer); + assert.equal(views.length, 3); + + // should not throw + grid.removeView(views[2]); + }); + + test('serialize should store visibility and previous size', function () { + const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new SerializableGrid(view1); + container.appendChild(grid.element); + grid.layout(800, 600); + + const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, 200, view1, Direction.Up); + + const view3 = new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, 200, view1, Direction.Right); + + const view4 = new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view4, 200, view2, Direction.Left); + + const view5 = new TestSerializableView('view5', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view5, 100, view1, Direction.Down); + + assert.deepEqual(view1.size, [600, 300]); + assert.deepEqual(view2.size, [600, 200]); + assert.deepEqual(view3.size, [200, 400]); + assert.deepEqual(view4.size, [200, 200]); + assert.deepEqual(view5.size, [600, 100]); + + grid.setViewVisible(view5, false); + + assert.deepEqual(view1.size, [600, 400]); + assert.deepEqual(view2.size, [600, 200]); + assert.deepEqual(view3.size, [200, 400]); + assert.deepEqual(view4.size, [200, 200]); + assert.deepEqual(view5.size, [600, 0]); + + grid.setViewVisible(view5, true); + + assert.deepEqual(view1.size, [600, 300]); + assert.deepEqual(view2.size, [600, 200]); + assert.deepEqual(view3.size, [200, 400]); + assert.deepEqual(view4.size, [200, 200]); + assert.deepEqual(view5.size, [600, 100]); + + grid.setViewVisible(view5, false); + + assert.deepEqual(view1.size, [600, 400]); + assert.deepEqual(view2.size, [600, 200]); + assert.deepEqual(view3.size, [200, 400]); + assert.deepEqual(view4.size, [200, 200]); + assert.deepEqual(view5.size, [600, 0]); + + grid.setViewVisible(view5, false); + + const json = grid.serialize(); + assert.deepEqual(json, { + orientation: 0, + width: 800, + height: 600, + root: { + type: 'branch', + data: [ + { + type: 'branch', + data: [ + { type: 'leaf', data: { name: 'view4' }, size: 200 }, + { type: 'leaf', data: { name: 'view2' }, size: 600 } + ], + size: 200 + }, + { + type: 'branch', + data: [ + { + type: 'branch', + data: [ + { type: 'leaf', data: { name: 'view1' }, size: 400 }, + { type: 'leaf', data: { name: 'view5' }, size: 100, visible: false } + ], + size: 600 + }, + { type: 'leaf', data: { name: 'view3' }, size: 200 } + ], + size: 400 + } + ], + size: 800 + } + }); + + grid.dispose(); + + const deserializer = new TestViewDeserializer(); + const grid2 = SerializableGrid.deserialize(json, deserializer); + + const view1Copy = deserializer.getView('view1'); + const view2Copy = deserializer.getView('view2'); + const view3Copy = deserializer.getView('view3'); + const view4Copy = deserializer.getView('view4'); + const view5Copy = deserializer.getView('view5'); + + assert.deepEqual(nodesToArrays(grid2.getViews()), [[view4Copy, view2Copy], [[view1Copy, view5Copy], view3Copy]]); + + grid2.layout(800, 600); + assert.deepEqual(view1Copy.size, [600, 400]); + assert.deepEqual(view2Copy.size, [600, 200]); + assert.deepEqual(view3Copy.size, [200, 400]); + assert.deepEqual(view4Copy.size, [200, 200]); + assert.deepEqual(view5Copy.size, [600, 0]); + + assert.deepEqual(grid2.isViewVisible(view1Copy), true); + assert.deepEqual(grid2.isViewVisible(view2Copy), true); + assert.deepEqual(grid2.isViewVisible(view3Copy), true); + assert.deepEqual(grid2.isViewVisible(view4Copy), true); + assert.deepEqual(grid2.isViewVisible(view5Copy), false); + + grid2.setViewVisible(view5Copy, true); + + assert.deepEqual(view1Copy.size, [600, 300]); + assert.deepEqual(view2Copy.size, [600, 200]); + assert.deepEqual(view3Copy.size, [200, 400]); + assert.deepEqual(view4Copy.size, [200, 200]); + assert.deepEqual(view5Copy.size, [600, 100]); + + assert.deepEqual(grid2.isViewVisible(view1Copy), true); + assert.deepEqual(grid2.isViewVisible(view2Copy), true); + assert.deepEqual(grid2.isViewVisible(view3Copy), true); + assert.deepEqual(grid2.isViewVisible(view4Copy), true); + assert.deepEqual(grid2.isViewVisible(view5Copy), true); + }); + + test('serialize should store visibility and previous size even for first leaf', function () { + const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new SerializableGrid(view1); + container.appendChild(grid.element); + grid.layout(800, 600); + + const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, 200, view1, Direction.Up); + + const view3 = new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, 200, view1, Direction.Right); + + const view4 = new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view4, 200, view2, Direction.Left); + + const view5 = new TestSerializableView('view5', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view5, 100, view1, Direction.Down); + + assert.deepEqual(view1.size, [600, 300]); + assert.deepEqual(view2.size, [600, 200]); + assert.deepEqual(view3.size, [200, 400]); + assert.deepEqual(view4.size, [200, 200]); + assert.deepEqual(view5.size, [600, 100]); + + grid.setViewVisible(view4, false); + + assert.deepEqual(view1.size, [600, 300]); + assert.deepEqual(view2.size, [800, 200]); + assert.deepEqual(view3.size, [200, 400]); + assert.deepEqual(view4.size, [0, 200]); + assert.deepEqual(view5.size, [600, 100]); + + const json = grid.serialize(); + assert.deepEqual(json, { + orientation: 0, + width: 800, + height: 600, + root: { + type: 'branch', + data: [ + { + type: 'branch', + data: [ + { type: 'leaf', data: { name: 'view4' }, size: 200, visible: false }, + { type: 'leaf', data: { name: 'view2' }, size: 800 } + ], + size: 200 + }, + { + type: 'branch', + data: [ + { + type: 'branch', + data: [ + { type: 'leaf', data: { name: 'view1' }, size: 300 }, + { type: 'leaf', data: { name: 'view5' }, size: 100 } + ], + size: 600 + }, + { type: 'leaf', data: { name: 'view3' }, size: 200 } + ], + size: 400 + } + ], + size: 800 + } + }); + + grid.dispose(); + + const deserializer = new TestViewDeserializer(); + const grid2 = SerializableGrid.deserialize(json, deserializer); + + const view1Copy = deserializer.getView('view1'); + const view2Copy = deserializer.getView('view2'); + const view3Copy = deserializer.getView('view3'); + const view4Copy = deserializer.getView('view4'); + const view5Copy = deserializer.getView('view5'); + + assert.deepEqual(nodesToArrays(grid2.getViews()), [[view4Copy, view2Copy], [[view1Copy, view5Copy], view3Copy]]); + + grid2.layout(800, 600); + assert.deepEqual(view1Copy.size, [600, 300]); + assert.deepEqual(view2Copy.size, [800, 200]); + assert.deepEqual(view3Copy.size, [200, 400]); + assert.deepEqual(view4Copy.size, [0, 200]); + assert.deepEqual(view5Copy.size, [600, 100]); + + assert.deepEqual(grid2.isViewVisible(view1Copy), true); + assert.deepEqual(grid2.isViewVisible(view2Copy), true); + assert.deepEqual(grid2.isViewVisible(view3Copy), true); + assert.deepEqual(grid2.isViewVisible(view4Copy), false); + assert.deepEqual(grid2.isViewVisible(view5Copy), true); + + grid2.setViewVisible(view4Copy, true); + + assert.deepEqual(view1Copy.size, [600, 300]); + assert.deepEqual(view2Copy.size, [600, 200]); + assert.deepEqual(view3Copy.size, [200, 400]); + assert.deepEqual(view4Copy.size, [200, 200]); + assert.deepEqual(view5Copy.size, [600, 100]); + + assert.deepEqual(grid2.isViewVisible(view1Copy), true); + assert.deepEqual(grid2.isViewVisible(view2Copy), true); + assert.deepEqual(grid2.isViewVisible(view3Copy), true); + assert.deepEqual(grid2.isViewVisible(view4Copy), true); + assert.deepEqual(grid2.isViewVisible(view5Copy), true); + }); +}); diff --git a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts index a74e6467c6..276b43a557 100644 --- a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts @@ -57,7 +57,7 @@ export class UserDataAutoSyncEnablementService extends Disposable { return true; case 'off': return false; - default: return this.storageService.getBoolean(enablementKey, StorageScope.GLOBAL, this.environmentService.enableSyncByDefault); + default: return this.storageService.getBoolean(enablementKey, StorageScope.GLOBAL, this.environmentService.enableSyncByDefault); // {{SQL CARBON EDIT}} strict-null-checks move this to a default case } } diff --git a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index 46ce3d3bb8..0d9ad58412 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -127,13 +127,11 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha } private static _reviveCodeActionDto(data: ReadonlyArray): modes.CodeAction[] { - let dataCast = data as unknown; // {{ SQL CARBON EDIT }} - let returnval = dataCast as modes.CodeAction[]; // {{ SQL CARBON EDIT }} - if (returnval) { + if (data) { data.forEach(code => reviveWorkspaceEditDto(code.edit)); } - return returnval; // {{ SQL CARBON EDIT }} + return data; // {{SQL CARBON EDIT}} strict-null-check } private static _reviveLinkDTO(data: ILinkDto): modes.ILink { diff --git a/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts index 276279cb7e..67661fbf85 100644 --- a/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -1083,7 +1083,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN const provider = this._notebookContentProviders.get(viewType); const revivedUri = URI.revive(uri); if (!provider) { - return undefined; // {{SQL CARBON EDIT}} + return undefined; // {{SQL CARBON EDIT}} strict-null-checks } const storageRoot = this._extensionStoragePaths.workspaceValue(provider.extension) ?? this._extensionStoragePaths.globalValue(provider.extension); diff --git a/src/vs/workbench/contrib/debug/browser/debugANSIHandling.ts b/src/vs/workbench/contrib/debug/browser/debugANSIHandling.ts index 7fd99519e4..0ef2488398 100644 --- a/src/vs/workbench/contrib/debug/browser/debugANSIHandling.ts +++ b/src/vs/workbench/contrib/debug/browser/debugANSIHandling.ts @@ -302,7 +302,7 @@ export function appendStylizedStringToContainer( export function calcANSI8bitColor(colorNumber: number): RGBA | undefined { if (colorNumber % 1 !== 0) { // Should be integer - // {{SQL CARBON EDIT}} @todo anthonydresser 4/12/19 this is necessary because we don't use strict null checks + // {{SQL CARBON EDIT}} @todo anthonydresser 4/12/19 this is necessary because we don't use strict-null-checks return undefined; } if (colorNumber >= 16 && colorNumber <= 231) { // Converts to one of 216 RGB colors @@ -327,7 +327,7 @@ export function calcANSI8bitColor(colorNumber: number): RGBA | undefined { const colorLevel: number = Math.round(colorNumber / 23 * 255); return new RGBA(colorLevel, colorLevel, colorLevel); } else { - // {{SQL CARBON EDIT}} @todo anthonydresser 4/12/19 this is necessary because we don't use strict null checks + // {{SQL CARBON EDIT}} @todo anthonydresser 4/12/19 this is necessary because we don't use strict-null-checks return undefined; } } diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts index 33b0e3353a..99a41d7b9b 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts @@ -160,9 +160,6 @@ abstract class NotebookAction extends Action2 { } const activeCell = editor.getActiveCell(); - if (!activeCell) { - return undefined; // {{SQL CARBON EDIT}} strict-null-checks - } return { cell: activeCell, diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts index bc00730166..cf18ddfbff 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts @@ -231,7 +231,6 @@ export class NotebookEditor extends EditorPane { return group.activeEditorPane._widget.value?.getEditorViewState(); } } - return undefined; // {{SQL CARBON EDIT}} strict-null-check } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 88fcae877c..c42dbad42f 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -192,8 +192,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor get activeCodeEditor(): IEditor | undefined { if (this._isDisposed) { - // {{SQL CARBON EDIT}} - return undefined; + return undefined; // {{SQL CARBON EDIT}} strict-null-check } const [focused] = this._list!.getFocusedElements(); @@ -769,14 +768,14 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor await this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel); if (tokenSource.token.isCancellationRequested) { - return undefined; // {{ SQL CARBON EDIT }} + return undefined; // {{SQL CARBON EDIT}} strict-null-check } this._activeKernelResolvePromise = (this.activeKernel as INotebookKernelInfo2).resolve(this.viewModel!.uri, this.getId(), tokenSource.token); await this._activeKernelResolvePromise; if (tokenSource.token.isCancellationRequested) { - return undefined; // {{ SQL CARBON EDIT }} + return undefined; // {{SQL CARBON EDIT}} strict-null-check } } diff --git a/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts b/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts index fbe0b55f7a..8726f6f820 100644 --- a/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts +++ b/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts @@ -306,7 +306,7 @@ export class SimpleFileDialog { this.filePickBox.onDidCustom(() => { if (isAcceptHandled || this.busy) { - return undefined; // {{SQL CARBON EDIT}} @todo anthonydresser return to return; when we do strict null checks + return undefined; // {{SQL CARBON EDIT}} @todo anthonydresser return to return; when we do strict-null-checks } isAcceptHandled = true; diff --git a/src/vs/workbench/services/search/node/ripgrepFileSearch.ts b/src/vs/workbench/services/search/node/ripgrepFileSearch.ts index 28fe3a432a..933e840451 100644 --- a/src/vs/workbench/services/search/node/ripgrepFileSearch.ts +++ b/src/vs/workbench/services/search/node/ripgrepFileSearch.ts @@ -145,7 +145,7 @@ function globExprsToRgGlobs(patterns: glob.IExpression, folder?: string, exclude } globArgs.push(fixDriveC(key)); - // {{SQL CARBON EDIT}} @todo anthonydresser 4/12/19 cast value because we aren't using strict null checks + // {{SQL CARBON EDIT}} @todo anthonydresser 4/12/19 cast value because we aren't using strict-null-checks } else if (value && (value).when) { siblingClauses[key] = value; } diff --git a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts index 15e4d64c36..b8efba8d40 100644 --- a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts @@ -37,12 +37,11 @@ import { isWeb } from 'vs/base/common/platform'; // implementation -const DEFAULT_COLOR_THEME_ID = 'vs sql-theme-carbon-themes-light_carbon-json'; +const DEFAULT_COLOR_THEME_ID = 'vs sql-theme-carbon-themes-light_carbon-json'; // {{SQL CARBON EDIT}} const PERSISTED_OS_COLOR_SCHEME = 'osColorScheme'; -// {{SQL CARBON EDIT}} -const defaultThemeExtensionId = 'sql-theme-carbon'; +const defaultThemeExtensionId = 'sql-theme-carbon';// {{SQL CARBON EDIT}} const oldDefaultThemeExtensionId = 'vscode-theme-colorful-defaults'; const DEFAULT_FILE_ICON_THEME_ID = 'vscode.vscode-theme-seti-vs-seti'; diff --git a/src/vs/workbench/services/themes/common/themeConfiguration.ts b/src/vs/workbench/services/themes/common/themeConfiguration.ts index e9cfcc5583..89614728b1 100644 --- a/src/vs/workbench/services/themes/common/themeConfiguration.ts +++ b/src/vs/workbench/services/themes/common/themeConfiguration.ts @@ -33,7 +33,7 @@ const colorThemeSettingEnumDescriptions: string[] = []; const colorThemeSettingSchema: IConfigurationPropertySchema = { type: 'string', description: nls.localize('colorTheme', "Specifies the color theme used in the workbench."), - default: isWeb ? DEFAULT_THEME_LIGHT_SETTING_VALUE : DEFAULT_THEME_LIGHT_SETTING_VALUE, + default: isWeb ? DEFAULT_THEME_LIGHT_SETTING_VALUE : DEFAULT_THEME_LIGHT_SETTING_VALUE, // {{SQL CARBON EDIT}} enum: colorThemeSettingEnum, enumDescriptions: colorThemeSettingEnumDescriptions, errorMessage: nls.localize('colorThemeError', "Theme is unknown or not installed."), diff --git a/src/vs/workbench/test/electron-browser/textsearch.perf.integrationTest.ts b/src/vs/workbench/test/electron-browser/textsearch.perf.integrationTest.ts index 15008fb757..1b840e70ca 100644 --- a/src/vs/workbench/test/electron-browser/textsearch.perf.integrationTest.ts +++ b/src/vs/workbench/test/electron-browser/textsearch.perf.integrationTest.ts @@ -141,7 +141,7 @@ suite.skip('TextSearch performance (integration)', () => { let i = n; return (function iterate(): Promise | undefined { if (!i--) { - return undefined; + return undefined; // {{SQL CARBON EDIT}} strict-null-checks } return runSearch()