diff --git a/src/vs/base/common/marshalling.ts b/src/vs/base/common/marshalling.ts index e8732b18ed2f8..789cdf08a1677 100644 --- a/src/vs/base/common/marshalling.ts +++ b/src/vs/base/common/marshalling.ts @@ -51,6 +51,7 @@ function replacer(key: string, value: any): any { type Deserialize = T extends UriComponents ? URI + : T extends VSBuffer ? VSBuffer : T extends object ? Revived : T; diff --git a/src/vs/workbench/api/browser/mainThreadNotebookDto.ts b/src/vs/workbench/api/browser/mainThreadNotebookDto.ts index 8d7a1f60a143b..f64c85e061bf3 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebookDto.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebookDto.ts @@ -12,7 +12,7 @@ export namespace NotebookDto { export function toNotebookOutputItemDto(item: notebookCommon.IOutputItemDto): extHostProtocol.NotebookOutputItemDto { return { mime: item.mime, - valueBytes: Array.from(item.data) + valueBytes: item.data }; } @@ -46,7 +46,7 @@ export namespace NotebookDto { export function fromNotebookOutputItemDto(item: extHostProtocol.NotebookOutputItemDto): notebookCommon.IOutputItemDto { return { mime: item.mime, - data: new Uint8Array(item.valueBytes) + data: item.valueBytes }; } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 4c530a5f7e4c4..eef25747916eb 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1938,7 +1938,7 @@ export interface INotebookDocumentsAndEditorsDelta { export interface NotebookOutputItemDto { readonly mime: string; - readonly valueBytes: number[]; // todo@jrieken ugly, should be VSBuffer + readonly valueBytes: VSBuffer; } export interface NotebookOutputDto { diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 6e5a72cab22b5..5d9cfd09c38dd 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { coalesce, isNonEmptyArray } from 'vs/base/common/arrays'; +import { VSBuffer } from 'vs/base/common/buffer'; import * as htmlContent from 'vs/base/common/htmlContent'; import { DisposableStore } from 'vs/base/common/lifecycle'; import * as marked from 'vs/base/common/marked/marked'; @@ -1494,12 +1495,12 @@ export namespace NotebookCellOutputItem { export function from(item: types.NotebookCellOutputItem): extHostProtocol.NotebookOutputItemDto { return { mime: item.mime, - valueBytes: Array.from(item.data), //todo@jrieken this HACKY and SLOW... hoist VSBuffer instead + valueBytes: VSBuffer.wrap(item.data), }; } export function to(item: extHostProtocol.NotebookOutputItemDto): types.NotebookCellOutputItem { - return new types.NotebookCellOutputItem(new Uint8Array(item.valueBytes), item.mime); + return new types.NotebookCellOutputItem(item.valueBytes.buffer, item.mime); } } diff --git a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts index d768558a3a021..fef2ccb414cbf 100644 --- a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts +++ b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts @@ -104,7 +104,7 @@ export class InteractiveDocumentContribution extends Disposable implements IWork outputId: output.outputId, outputs: output.outputs.map(ot => ({ mime: ot.mime, - data: Uint8Array.from(ot.data) + data: ot.data })) })) : [], @@ -145,7 +145,7 @@ export class InteractiveDocumentContribution extends Disposable implements IWork outputId: output.outputId, outputs: output.outputs.map(ot => ({ mime: ot.mime, - data: Array.from(ot.data) + data: ot.data })) }; }), diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/codeRenderer/codeRenderer.ts b/src/vs/workbench/contrib/notebook/browser/contrib/codeRenderer/codeRenderer.ts index f586e91e97714..fcb96a0ead1c4 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/codeRenderer/codeRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/codeRenderer/codeRenderer.ts @@ -123,7 +123,7 @@ workbenchContributionsRegistry.registerWorkbenchContribution(NotebookCodeRendere // --- utils --- function getStringValue(item: IOutputItemDto): string { // todo@jrieken NOT proper, should be VSBuffer - return new TextDecoder().decode(item.data); + return new TextDecoder().decode(item.data.buffer); } function getOutputSimpleEditorOptions(): IEditorConstructionOptions { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts index 26e5cc8395cb6..5a0073f9c9269 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts @@ -515,12 +515,12 @@ function outputsEqual(original: ICellOutput[], modified: ICellOutput[]) { return false; } - if (aOutputItem.data.length !== bOutputItem.data.length) { + if (aOutputItem.data.buffer.length !== bOutputItem.data.buffer.length) { return false; } - for (let k = 0; k < aOutputItem.data.length; k++) { - if (aOutputItem.data[k] !== bOutputItem.data[k]) { + for (let k = 0; k < aOutputItem.data.buffer.length; k++) { + if (aOutputItem.data.buffer[k] !== bOutputItem.data.buffer[k]) { return false; } } diff --git a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts index 58132aff89e05..8142ff418d90d 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts @@ -370,7 +370,7 @@ class CellInfoContentProvider { const sameStream = !outputs.find(op => op.mime !== mime); if (sameStream) { - return outputs.map(opit => new TextDecoder().decode(opit.data)).join(''); + return outputs.map(opit => new TextDecoder().decode(opit.data.buffer)).join(''); } else { return null; } @@ -411,7 +411,7 @@ class CellInfoContentProvider { metadata: output.metadata, outputItems: output.outputs.map(opit => ({ mimeType: opit.mime, - data: new TextDecoder().decode(opit.data) + data: new TextDecoder().decode(opit.data.buffer) })) }))); const edits = format(content, undefined, {}); diff --git a/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts index ed87e35123683..a2afe5161a0b9 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts @@ -254,7 +254,7 @@ class ImgRendererContrib extends Disposable implements IOutputRendererContributi render(output: ICellOutputViewModel, item: IOutputItemDto, container: HTMLElement, notebookUri: URI): IRenderOutput { const disposable = new DisposableStore(); - const blob = new Blob([item.data], { type: item.mime }); + const blob = new Blob([item.data.buffer], { type: item.mime }); const src = URL.createObjectURL(blob); disposable.add(toDisposable(() => URL.revokeObjectURL(src))); @@ -281,6 +281,5 @@ OutputRendererRegistry.registerOutputTransform(StderrRendererContrib); // --- utils --- export function getStringValue(item: IOutputItemDto): string { - // todo@jrieken NOT proper, should be VSBuffer - return new TextDecoder().decode(item.data); + return item.data.buffer.toString(); } 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 9e626ee02407e..a0469e0eae88d 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -979,7 +979,7 @@ export class BackLayerWebView extends Disposable { type: RenderOutputType.Extension, outputId: output.outputId, mimeType: first.mime, - valueBytes: first.data, + valueBytes: first.data.buffer, metadata: output.metadata, }, }; diff --git a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts index f79ea2483898c..e3210e4eeda29 100644 --- a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts +++ b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts @@ -1016,7 +1016,7 @@ class OutputSequence implements ISequence { return this.outputs.map(output => { return hash(output.outputs.map(output => ({ mime: output.mime, - data: Array.from(output.data) + data: output.data }))); }); } diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index 7a2ad86414ec3..d534b8081a051 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { VSBuffer } from 'vs/base/common/buffer'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IDiffResult, ISequence } from 'vs/base/common/diff/diff'; import { Event } from 'vs/base/common/event'; @@ -157,7 +158,7 @@ export interface IOrderedMimeType { export interface IOutputItemDto { readonly mime: string; - readonly data: Uint8Array; + readonly data: VSBuffer; } export interface IOutputDto { diff --git a/src/vs/workbench/contrib/notebook/common/services/notebookSimpleWorker.ts b/src/vs/workbench/contrib/notebook/common/services/notebookSimpleWorker.ts index 27cd8990a688e..4313fb843487e 100644 --- a/src/vs/workbench/contrib/notebook/common/services/notebookSimpleWorker.ts +++ b/src/vs/workbench/contrib/notebook/common/services/notebookSimpleWorker.ts @@ -74,7 +74,7 @@ class MirrorCell { this._hash = hash([hash(this.language), hash(this.getValue()), this.metadata, this.internalMetadata, this.outputs.map(op => ({ outputs: op.outputs.map(output => ({ mime: output.mime, - data: Array.from(output.data) + data: output.data })), metadata: op.metadata }))]); diff --git a/src/vs/workbench/contrib/notebook/test/notebookDiff.test.ts b/src/vs/workbench/contrib/notebook/test/notebookDiff.test.ts index bf204572dd39d..2bbf84eef4bf0 100644 --- a/src/vs/workbench/contrib/notebook/test/notebookDiff.test.ts +++ b/src/vs/workbench/contrib/notebook/test/notebookDiff.test.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; +import { VSBuffer } from 'vs/base/common/buffer'; import { LcsDiff } from 'vs/base/common/diff/diff'; import { Mimes } from 'vs/base/common/mime'; import { NotebookDiffEditorEventDispatcher } from 'vs/workbench/contrib/notebook/browser/diff/eventDispatcher'; @@ -15,9 +16,9 @@ suite('NotebookCommon', () => { test('diff different source', async () => { await withTestNotebookDiffModel([ - ['x', 'javascript', CellKind.Code, [{ outputId: 'someOtherId', outputs: [{ mime: Mimes.text, data: new Uint8Array([3]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 3 }], + ['x', 'javascript', CellKind.Code, [{ outputId: 'someOtherId', outputs: [{ mime: Mimes.text, data: VSBuffer.wrap(new Uint8Array([3])) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 3 }], ], [ - ['y', 'javascript', CellKind.Code, [{ outputId: 'someOtherId', outputs: [{ mime: Mimes.text, data: new Uint8Array([3]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 3 }], + ['y', 'javascript', CellKind.Code, [{ outputId: 'someOtherId', outputs: [{ mime: Mimes.text, data: VSBuffer.wrap(new Uint8Array([3])) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 3 }], ], (model, accessor) => { const diff = new LcsDiff(new CellSequence(model.original.notebook), new CellSequence(model.modified.notebook)); const diffResult = diff.ComputeDiff(false); @@ -45,10 +46,10 @@ suite('NotebookCommon', () => { test('diff different output', async () => { await withTestNotebookDiffModel([ - ['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([5]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 5 }], + ['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: VSBuffer.wrap(new Uint8Array([5])) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 5 }], ['', 'javascript', CellKind.Code, [], {}] ], [ - ['x', 'javascript', CellKind.Code, [{ outputId: 'someOtherId', outputs: [{ mime: Mimes.text, data: new Uint8Array([3]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 3 }], + ['x', 'javascript', CellKind.Code, [{ outputId: 'someOtherId', outputs: [{ mime: Mimes.text, data: VSBuffer.wrap(new Uint8Array([3])) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 3 }], ['', 'javascript', CellKind.Code, [], {}] ], (model, accessor) => { const diff = new LcsDiff(new CellSequence(model.original.notebook), new CellSequence(model.modified.notebook)); @@ -146,12 +147,12 @@ suite('NotebookCommon', () => { test('diff foo/foe', async () => { await withTestNotebookDiffModel([ - [['def foe(x, y):\n', ' return x + y\n', 'foe(3, 2)'].join(''), 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([6]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 5 }], - [['def foo(x, y):\n', ' return x * y\n', 'foo(1, 2)'].join(''), 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([2]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 6 }], + [['def foe(x, y):\n', ' return x + y\n', 'foe(3, 2)'].join(''), 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: VSBuffer.wrap(new Uint8Array([6])) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 5 }], + [['def foo(x, y):\n', ' return x * y\n', 'foo(1, 2)'].join(''), 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: VSBuffer.wrap(new Uint8Array([2])) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 6 }], ['', 'javascript', CellKind.Code, [], {}] ], [ - [['def foo(x, y):\n', ' return x * y\n', 'foo(1, 2)'].join(''), 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([6]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 5 }], - [['def foe(x, y):\n', ' return x + y\n', 'foe(3, 2)'].join(''), 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([2]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 6 }], + [['def foo(x, y):\n', ' return x * y\n', 'foo(1, 2)'].join(''), 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: VSBuffer.wrap(new Uint8Array([6])) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 5 }], + [['def foe(x, y):\n', ' return x + y\n', 'foe(3, 2)'].join(''), 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: VSBuffer.wrap(new Uint8Array([2])) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 6 }], ['', 'javascript', CellKind.Code, [], {}] ], (model, accessor) => { const diff = new LcsDiff(new CellSequence(model.original.notebook), new CellSequence(model.modified.notebook)); @@ -273,13 +274,13 @@ suite('NotebookCommon', () => { await withTestNotebookDiffModel([ ['# Description', 'markdown', CellKind.Markup, [], { custom: { metadata: {} } }], ['x = 3', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: true } }, executionOrder: 1 }], - ['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([3]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 1 }], + ['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: VSBuffer.wrap(new Uint8Array([3])) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 1 }], ['x', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: false } } }] ], [ ['# Description', 'markdown', CellKind.Markup, [], { custom: { metadata: {} } }], ['x = 3', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: true } }, executionOrder: 1 }], ['x', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: false } } }], - ['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([3]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 1 }] + ['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: VSBuffer.wrap(new Uint8Array([3])) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 1 }] ], async (model) => { const diff = new LcsDiff(new CellSequence(model.original.notebook), new CellSequence(model.modified.notebook)); const diffResult = diff.ComputeDiff(false); @@ -306,18 +307,18 @@ suite('NotebookCommon', () => { await withTestNotebookDiffModel([ ['# Description', 'markdown', CellKind.Markup, [], { custom: { metadata: {} } }], ['x = 3', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: true } }, executionOrder: 1 }], - ['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([3]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 1 }], + ['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: VSBuffer.wrap(new Uint8Array([3])) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 1 }], ['x', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: false } } }], ['x = 5', 'javascript', CellKind.Code, [], {}], ['x', 'javascript', CellKind.Code, [], {}], - ['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([5]) }] }], {}], + ['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: VSBuffer.wrap(new Uint8Array([5])) }] }], {}], ], [ ['# Description', 'markdown', CellKind.Markup, [], { custom: { metadata: {} } }], ['x = 3', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: true } }, executionOrder: 1 }], ['x', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: false } } }], - ['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([3]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 1 }], + ['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: VSBuffer.wrap(new Uint8Array([3])) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 1 }], ['x = 5', 'javascript', CellKind.Code, [], {}], - ['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([5]) }] }], {}], + ['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: VSBuffer.wrap(new Uint8Array([5])) }] }], {}], ['x', 'javascript', CellKind.Code, [], {}], ], async (model) => { const diff = new LcsDiff(new CellSequence(model.original.notebook), new CellSequence(model.modified.notebook)); diff --git a/src/vs/workbench/contrib/notebook/test/notebookTextModel.test.ts b/src/vs/workbench/contrib/notebook/test/notebookTextModel.test.ts index ba773781edd79..a5e3bc53ade8d 100644 --- a/src/vs/workbench/contrib/notebook/test/notebookTextModel.test.ts +++ b/src/vs/workbench/contrib/notebook/test/notebookTextModel.test.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; +import { VSBuffer } from 'vs/base/common/buffer'; import { Mimes } from 'vs/base/common/mime'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; @@ -426,7 +427,7 @@ suite('NotebookTextModel', () => { const success1 = model.applyEdits( [{ editType: CellEditType.Output, index: 0, outputs: [ - { outputId: 'out1', outputs: [{ mime: 'application/x.notebook.stream', data: new Uint8Array([1]) }] } + { outputId: 'out1', outputs: [{ mime: 'application/x.notebook.stream', data: VSBuffer.wrap(new Uint8Array([1])) }] } ], append: false }], true, undefined, () => undefined, undefined, false @@ -438,7 +439,7 @@ suite('NotebookTextModel', () => { const success2 = model.applyEdits( [{ editType: CellEditType.Output, index: 0, outputs: [ - { outputId: 'out2', outputs: [{ mime: 'application/x.notebook.stream', data: new Uint8Array([1]) }] } + { outputId: 'out2', outputs: [{ mime: 'application/x.notebook.stream', data: VSBuffer.wrap(new Uint8Array([1])) }] } ], append: true }], true, undefined, () => undefined, undefined, false @@ -465,7 +466,7 @@ suite('NotebookTextModel', () => { const success = model.applyEdits( [{ editType: CellEditType.Output, index: 0, outputs: [ - { outputId: 'out1', outputs: [{ mime: 'application/x.notebook.stream', data: new Uint8Array([1]) }] } + { outputId: 'out1', outputs: [{ mime: 'application/x.notebook.stream', data: VSBuffer.wrap(new Uint8Array([1])) }] } ], append: false }], true, undefined, () => undefined, undefined, false diff --git a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts index c5322cef25f17..43cf0ac136d99 100644 --- a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts @@ -47,6 +47,7 @@ import { NotebookOptions } from 'vs/workbench/contrib/notebook/common/notebookOp import { ViewContext } from 'vs/workbench/contrib/notebook/browser/viewModel/viewContext'; import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; import { Mimes } from 'vs/base/common/mime'; +import { VSBuffer } from 'vs/base/common/buffer'; export class TestCell extends NotebookCellTextModel { constructor( @@ -345,6 +346,6 @@ export function createNotebookCellList(instantiationService: TestInstantiationSe return cellList; } -export function valueBytesFromString(value: string) { - return new TextEncoder().encode(value); +export function valueBytesFromString(value: string): VSBuffer { + return VSBuffer.wrap(new TextEncoder().encode(value)); } diff --git a/src/vs/workbench/services/extensions/common/rpcProtocol.ts b/src/vs/workbench/services/extensions/common/rpcProtocol.ts index 8e1d9ee523f7d..9e9cb8c0fecb7 100644 --- a/src/vs/workbench/services/extensions/common/rpcProtocol.ts +++ b/src/vs/workbench/services/extensions/common/rpcProtocol.ts @@ -14,7 +14,7 @@ import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { LazyPromise } from 'vs/workbench/services/extensions/common/lazyPromise'; import { IRPCProtocol, ProxyIdentifier, getStringIdentifierForProxy } from 'vs/workbench/services/extensions/common/proxyIdentifier'; import { VSBuffer } from 'vs/base/common/buffer'; -import { MarshalledId } from 'vs/base/common/marshalling'; +import { MarshalledId, MarshalledObject } from 'vs/base/common/marshalling'; export interface JSONStringifyReplacer { (key: string, value: any): any; @@ -28,10 +28,6 @@ function safeStringify(obj: any, replacer: JSONStringifyReplacer | null): string } } -function stringify(obj: any, replacer: JSONStringifyReplacer | null): string { - return JSON.stringify(obj, <(key: string, value: any) => any>replacer); -} - function createURIReplacer(transformer: IURITransformer | null): JSONStringifyReplacer | null { if (!transformer) { return null; @@ -237,22 +233,10 @@ export class RPCProtocol extends Disposable implements IRPCProtocol { const req = buff.readUInt32(); switch (messageType) { - case MessageType.RequestJSONArgs: - case MessageType.RequestJSONArgsWithCancellation: { - let { rpcId, method, args } = MessageIO.deserializeRequestJSONArgs(buff); - if (this._uriTransformer) { - args = transformIncomingURIs(args, this._uriTransformer); - } - this._receiveRequest(msgLength, req, rpcId, method, args, (messageType === MessageType.RequestJSONArgsWithCancellation)); - break; - } - case MessageType.RequestMixedArgs: - case MessageType.RequestMixedArgsWithCancellation: { - let { rpcId, method, args } = MessageIO.deserializeRequestMixedArgs(buff); - if (this._uriTransformer) { - args = transformIncomingURIs(args, this._uriTransformer); - } - this._receiveRequest(msgLength, req, rpcId, method, args, (messageType === MessageType.RequestMixedArgsWithCancellation)); + case MessageType.RequestArgs: + case MessageType.RequestArgsWithCancellation: { + const { rpcId, method, args } = MessageIO.deserializeRequest(buff, this._uriTransformer); + this._receiveRequest(msgLength, req, rpcId, method, args, (messageType === MessageType.RequestArgsWithCancellation)); break; } case MessageType.Acknowledged: { @@ -558,177 +542,93 @@ class MessageBuffer { return buff; } - public static sizeMixedArray(arr: VSBuffer[], arrType: ArgType[]): number { - let size = 0; - size += 1; // arr length - for (let i = 0, len = arr.length; i < len; i++) { - const el = arr[i]; - const elType = arrType[i]; - size += 1; // arg type - switch (elType) { - case ArgType.String: - size += this.sizeLongString(el); - break; - case ArgType.VSBuffer: - size += this.sizeVSBuffer(el); - break; - case ArgType.Undefined: - // empty... - break; - } - } - return size; - } - - public writeMixedArray(arr: VSBuffer[], arrType: ArgType[]): void { - this._buff.writeUInt8(arr.length, this._offset); this._offset += 1; - for (let i = 0, len = arr.length; i < len; i++) { - const el = arr[i]; - const elType = arrType[i]; - switch (elType) { - case ArgType.String: - this.writeUInt8(ArgType.String); - this.writeLongString(el); - break; - case ArgType.VSBuffer: - this.writeUInt8(ArgType.VSBuffer); - this.writeVSBuffer(el); - break; - case ArgType.Undefined: - this.writeUInt8(ArgType.Undefined); - break; - } - } - } - - public readMixedArray(): Array { - const arrLen = this._buff.readUInt8(this._offset); this._offset += 1; - let arr: Array = new Array(arrLen); - for (let i = 0; i < arrLen; i++) { - const argType = this.readUInt8(); - switch (argType) { - case ArgType.String: - arr[i] = this.readLongString(); - break; - case ArgType.VSBuffer: - arr[i] = this.readVSBuffer(); - break; - case ArgType.Undefined: - arr[i] = undefined; - break; - } - } - return arr; - } } -type SerializedRequestArguments = { type: 'mixed'; args: VSBuffer[]; argsType: ArgType[]; } | { type: 'simple'; args: string; }; +const refSymbolName = '$$ref$$'; -class MessageIO { +interface SerializedRequestArguments { + readonly args: string; + readonly buffers: readonly VSBuffer[] | undefined; +} - private static _arrayContainsBufferOrUndefined(arr: any[]): boolean { - for (let i = 0, len = arr.length; i < len; i++) { - if (arr[i] instanceof VSBuffer) { - return true; - } - if (typeof arr[i] === 'undefined') { - return true; - } - } - return false; - } +class MessageIO { public static serializeRequestArguments(args: any[], replacer: JSONStringifyReplacer | null): SerializedRequestArguments { - if (this._arrayContainsBufferOrUndefined(args)) { - let massagedArgs: VSBuffer[] = []; - let massagedArgsType: ArgType[] = []; - for (let i = 0, len = args.length; i < len; i++) { - const arg = args[i]; - if (arg instanceof VSBuffer) { - massagedArgs[i] = arg; - massagedArgsType[i] = ArgType.VSBuffer; - } else if (typeof arg === 'undefined') { - massagedArgs[i] = VSBuffer.alloc(0); - massagedArgsType[i] = ArgType.Undefined; - } else { - massagedArgs[i] = VSBuffer.fromString(stringify(arg, replacer)); - massagedArgsType[i] = ArgType.String; + const foundBuffers: VSBuffer[] = []; + const serializedArgs = JSON.stringify(args, (key, value) => { + if (typeof value === 'undefined') { + return { [refSymbolName]: -1 }; // JSON.stringify normally converts to 'null' + } else if (typeof value === 'object') { + if (value instanceof VSBuffer) { + const bufferIndex = foundBuffers.push(value) - 1; + return { [refSymbolName]: bufferIndex }; + } + if (replacer) { + return replacer(key, value); } } - return { - type: 'mixed', - args: massagedArgs, - argsType: massagedArgsType - }; - } + return value; + }); return { - type: 'simple', - args: stringify(args, replacer) + args: serializedArgs, + buffers: foundBuffers }; } public static serializeRequest(req: number, rpcId: number, method: string, serializedArgs: SerializedRequestArguments, usesCancellationToken: boolean): VSBuffer { - if (serializedArgs.type === 'mixed') { - return this._requestMixedArgs(req, rpcId, method, serializedArgs.args, serializedArgs.argsType, usesCancellationToken); - } - return this._requestJSONArgs(req, rpcId, method, serializedArgs.args, usesCancellationToken); - } - - private static _requestJSONArgs(req: number, rpcId: number, method: string, args: string, usesCancellationToken: boolean): VSBuffer { const methodBuff = VSBuffer.fromString(method); - const argsBuff = VSBuffer.fromString(args); + const argsBuff = VSBuffer.fromString(serializedArgs.args); let len = 0; len += MessageBuffer.sizeUInt8(); len += MessageBuffer.sizeShortString(methodBuff); len += MessageBuffer.sizeLongString(argsBuff); + len += MessageBuffer.sizeUInt8(); // buffer count + if (serializedArgs.buffers) { + for (const buffer of serializedArgs.buffers) { + len += MessageBuffer.sizeVSBuffer(buffer); + } + } - let result = MessageBuffer.alloc(usesCancellationToken ? MessageType.RequestJSONArgsWithCancellation : MessageType.RequestJSONArgs, req, len); + let result = MessageBuffer.alloc(usesCancellationToken ? MessageType.RequestArgsWithCancellation : MessageType.RequestArgs, req, len); result.writeUInt8(rpcId); result.writeShortString(methodBuff); result.writeLongString(argsBuff); + result.writeUInt8(serializedArgs.buffers?.length ?? 0); + if (serializedArgs.buffers) { + for (const buffer of serializedArgs.buffers) { + result.writeBuffer(buffer); + } + } + return result.buffer; } - public static deserializeRequestJSONArgs(buff: MessageBuffer): { rpcId: number; method: string; args: any[]; } { + public static deserializeRequest(buff: MessageBuffer, uriTransformer: IURITransformer | null): { rpcId: number; method: string; args: any[]; } { const rpcId = buff.readUInt8(); const method = buff.readShortString(); - const args = buff.readLongString(); - return { - rpcId: rpcId, - method: method, - args: JSON.parse(args) - }; - } - - private static _requestMixedArgs(req: number, rpcId: number, method: string, args: VSBuffer[], argsType: ArgType[], usesCancellationToken: boolean): VSBuffer { - const methodBuff = VSBuffer.fromString(method); + const rawargs = buff.readLongString(); + const bufferCount = buff.readUInt8(); - let len = 0; - len += MessageBuffer.sizeUInt8(); - len += MessageBuffer.sizeShortString(methodBuff); - len += MessageBuffer.sizeMixedArray(args, argsType); + const buffers: VSBuffer[] = []; + for (let i = 0; i < bufferCount; ++i) { + buffers.push(buff.readVSBuffer()); + } - let result = MessageBuffer.alloc(usesCancellationToken ? MessageType.RequestMixedArgsWithCancellation : MessageType.RequestMixedArgs, req, len); - result.writeUInt8(rpcId); - result.writeShortString(methodBuff); - result.writeMixedArray(args, argsType); - return result.buffer; - } + const args = JSON.parse(rawargs, (_key, value) => { + if (value) { + const ref = value[refSymbolName]; + if (typeof ref === 'number') { + return buffers[ref]; + } - public static deserializeRequestMixedArgs(buff: MessageBuffer): { rpcId: number; method: string; args: any[]; } { - const rpcId = buff.readUInt8(); - const method = buff.readShortString(); - const rawargs = buff.readMixedArray(); - const args: any[] = new Array(rawargs.length); - for (let i = 0, len = rawargs.length; i < len; i++) { - const rawarg = rawargs[i]; - if (typeof rawarg === 'string') { - args[i] = JSON.parse(rawarg); - } else { - args[i] = rawarg; + if (uriTransformer && (value).$mid === MarshalledId.Uri) { + return uriTransformer.transformIncoming(value); + } } - } + return value; + }); + return { rpcId: rpcId, method: method, @@ -816,10 +716,10 @@ class MessageIO { } const enum MessageType { - RequestJSONArgs = 1, - RequestJSONArgsWithCancellation = 2, - RequestMixedArgs = 3, - RequestMixedArgsWithCancellation = 4, + // RequestJSONArgs = 1, + // RequestJSONArgsWithCancellation = 2, + RequestArgs = 3, + RequestArgsWithCancellation = 4, Acknowledged = 5, Cancel = 6, ReplyOKEmpty = 7, @@ -829,8 +729,3 @@ const enum MessageType { ReplyErrEmpty = 11, } -const enum ArgType { - String = 1, - VSBuffer = 2, - Undefined = 3 -}