mirror of
https://github.com/Microsoft/vscode
synced 2024-10-12 06:17:18 +00:00
Revert "Merge pull request #131592 from DonJayamanne/revertPerfFixes2"
This reverts commit52baabff07
, reversing changes made to6e930fb6d4
.
This commit is contained in:
parent
52baabff07
commit
31abc3784e
|
@ -53,18 +53,37 @@ const orderOfMimeTypes = [
|
|||
'text/plain'
|
||||
];
|
||||
|
||||
function isEmptyVendoredMimeType(outputItem: NotebookCellOutputItem) {
|
||||
if (outputItem.mime.startsWith('application/vnd.')) {
|
||||
try {
|
||||
return outputItem.data.byteLength === 0 || Buffer.from(outputItem.data).toString().length === 0;
|
||||
} catch { }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function isMimeTypeMatch(value: string, compareWith: string) {
|
||||
if (value.endsWith('.*')) {
|
||||
value = value.substr(0, value.indexOf('.*'));
|
||||
}
|
||||
return compareWith.startsWith(value);
|
||||
}
|
||||
|
||||
function sortOutputItemsBasedOnDisplayOrder(outputItems: NotebookCellOutputItem[]): NotebookCellOutputItem[] {
|
||||
return outputItems.sort((outputItemA, outputItemB) => {
|
||||
const isMimeTypeMatch = (value: string, compareWith: string) => {
|
||||
if (value.endsWith('.*')) {
|
||||
value = value.substr(0, value.indexOf('.*'));
|
||||
return outputItems
|
||||
.map(item => {
|
||||
let index = orderOfMimeTypes.findIndex((mime) => isMimeTypeMatch(mime, item.mime));
|
||||
// Sometimes we can have mime types with empty data, e.g. when using holoview we can have `application/vnd.holoviews_load.v0+json` with empty value.
|
||||
// & in these cases we have HTML/JS and those take precedence.
|
||||
// https://github.com/microsoft/vscode-jupyter/issues/6109
|
||||
if (isEmptyVendoredMimeType(item)) {
|
||||
index = -1;
|
||||
}
|
||||
return compareWith.startsWith(value);
|
||||
};
|
||||
const indexOfMimeTypeA = orderOfMimeTypes.findIndex(mime => isMimeTypeMatch(outputItemA.mime, mime));
|
||||
const indexOfMimeTypeB = orderOfMimeTypes.findIndex(mime => isMimeTypeMatch(outputItemB.mime, mime));
|
||||
return indexOfMimeTypeA - indexOfMimeTypeB;
|
||||
});
|
||||
index = index === -1 ? 100 : index;
|
||||
return {
|
||||
item, index
|
||||
};
|
||||
})
|
||||
.sort((outputItemA, outputItemB) => outputItemA.index - outputItemB.index).map(item => item.item);
|
||||
}
|
||||
|
||||
|
||||
|
@ -237,7 +256,7 @@ cellOutputMappers.set('update_display_data', translateDisplayDataOutput);
|
|||
cellOutputMappers.set('error', translateErrorOutput);
|
||||
cellOutputMappers.set('stream', translateStreamOutput);
|
||||
|
||||
function jupyterCellOutputToCellOutput(output: nbformat.IOutput): NotebookCellOutput {
|
||||
export function jupyterCellOutputToCellOutput(output: nbformat.IOutput): NotebookCellOutput {
|
||||
/**
|
||||
* Stream, `application/x.notebook.stream`
|
||||
* Error, `application/x.notebook.error-traceback`
|
||||
|
|
|
@ -40,8 +40,8 @@ export class NotebookSerializer implements vscode.NotebookSerializer {
|
|||
}
|
||||
}
|
||||
|
||||
// Then compute indent from the contents
|
||||
const indentAmount = contents ? detectIndent(contents).indent : ' ';
|
||||
// Then compute indent from the contents (only use first 1K characters as a perf optimization)
|
||||
const indentAmount = contents ? detectIndent(contents.substring(0, 1_000)).indent : ' ';
|
||||
|
||||
const preferredCellLanguage = getPreferredLanguage(json.metadata);
|
||||
// Ensure we always have a blank cell.
|
||||
|
|
|
@ -94,7 +94,7 @@ function translateCellDisplayOutput(output: NotebookCellOutput): JupyterOutput {
|
|||
case 'display_data': {
|
||||
result = {
|
||||
output_type: 'display_data',
|
||||
data: output.items.reduceRight((prev: any, curr) => {
|
||||
data: output.items.reduce((prev: any, curr) => {
|
||||
prev[curr.mime] = convertOutputMimeToJupyterOutput(curr.mime, curr.data as Uint8Array);
|
||||
return prev;
|
||||
}, {}),
|
||||
|
@ -105,7 +105,7 @@ function translateCellDisplayOutput(output: NotebookCellOutput): JupyterOutput {
|
|||
case 'execute_result': {
|
||||
result = {
|
||||
output_type: 'execute_result',
|
||||
data: output.items.reduceRight((prev: any, curr) => {
|
||||
data: output.items.reduce((prev: any, curr) => {
|
||||
prev[curr.mime] = convertOutputMimeToJupyterOutput(curr.mime, curr.data as Uint8Array);
|
||||
return prev;
|
||||
}, {}),
|
||||
|
@ -118,7 +118,7 @@ function translateCellDisplayOutput(output: NotebookCellOutput): JupyterOutput {
|
|||
case 'update_display_data': {
|
||||
result = {
|
||||
output_type: 'update_display_data',
|
||||
data: output.items.reduceRight((prev: any, curr) => {
|
||||
data: output.items.reduce((prev: any, curr) => {
|
||||
prev[curr.mime] = convertOutputMimeToJupyterOutput(curr.mime, curr.data as Uint8Array);
|
||||
return prev;
|
||||
}, {}),
|
||||
|
@ -163,7 +163,7 @@ function translateCellDisplayOutput(output: NotebookCellOutput): JupyterOutput {
|
|||
unknownOutput.metadata = customMetadata.metadata;
|
||||
}
|
||||
if (output.items.length > 0) {
|
||||
unknownOutput.data = output.items.reduceRight((prev: any, curr) => {
|
||||
unknownOutput.data = output.items.reduce((prev: any, curr) => {
|
||||
prev[curr.mime] = convertOutputMimeToJupyterOutput(curr.mime, curr.data as Uint8Array);
|
||||
return prev;
|
||||
}, {});
|
||||
|
@ -224,17 +224,33 @@ type JupyterOutput =
|
|||
| nbformat.IError;
|
||||
|
||||
function convertStreamOutput(output: NotebookCellOutput): JupyterOutput {
|
||||
const outputs = output.items
|
||||
const outputs: string[] = [];
|
||||
output.items
|
||||
.filter((opit) => opit.mime === CellOutputMimeTypes.stderr || opit.mime === CellOutputMimeTypes.stdout)
|
||||
.map((opit) => convertOutputMimeToJupyterOutput(opit.mime, opit.data as Uint8Array) as string)
|
||||
.reduceRight<string[]>((prev, curr) => prev.concat(curr), []);
|
||||
.forEach(value => {
|
||||
// Ensure each line is a seprate entry in an array (ending with \n).
|
||||
const lines = value.split('\n');
|
||||
// If the last item in `outputs` is not empty and the first item in `lines` is not empty, then concate them.
|
||||
// As they are part of the same line.
|
||||
if (outputs.length && lines.length && lines[0].length > 0) {
|
||||
outputs[outputs.length - 1] = `${outputs[outputs.length - 1]}${lines.shift()!}`;
|
||||
}
|
||||
for (const line of lines) {
|
||||
outputs.push(line);
|
||||
}
|
||||
});
|
||||
// Skip last one if empty (it's the only one that could be length 0)
|
||||
if (outputs.length && outputs[outputs.length - 1].length === 0) {
|
||||
outputs.pop();
|
||||
}
|
||||
|
||||
const streamType = getOutputStreamType(output) || 'stdout';
|
||||
|
||||
return {
|
||||
output_type: 'stream',
|
||||
name: streamType,
|
||||
text: splitMultilineString(outputs.join(''))
|
||||
text: outputs
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import { nbformat } from '@jupyterlab/coreutils';
|
||||
import * as assert from 'assert';
|
||||
import * as vscode from 'vscode';
|
||||
import { jupyterNotebookModelToNotebookData } from '../deserializers';
|
||||
import { jupyterCellOutputToCellOutput, jupyterNotebookModelToNotebookData } from '../deserializers';
|
||||
|
||||
function deepStripProperties(obj: any, props: string[]) {
|
||||
for (let prop in obj) {
|
||||
|
@ -52,7 +52,6 @@ suite('ipynb serializer', () => {
|
|||
|
||||
assert.deepStrictEqual(notebook.cells, [expectedCodeCell, expectedMarkdownCell]);
|
||||
});
|
||||
|
||||
suite('Outputs', () => {
|
||||
function validateCellOutputTranslation(
|
||||
outputs: nbformat.IOutput[],
|
||||
|
@ -107,6 +106,81 @@ suite('ipynb serializer', () => {
|
|||
]
|
||||
);
|
||||
});
|
||||
test('Multi-line Stream output', () => {
|
||||
validateCellOutputTranslation(
|
||||
[
|
||||
{
|
||||
name: 'stdout',
|
||||
output_type: 'stream',
|
||||
text: [
|
||||
'Epoch 1/5\n',
|
||||
'...\n',
|
||||
'Epoch 2/5\n',
|
||||
'...\n',
|
||||
'Epoch 3/5\n',
|
||||
'...\n',
|
||||
'Epoch 4/5\n',
|
||||
'...\n',
|
||||
'Epoch 5/5\n',
|
||||
'...\n'
|
||||
]
|
||||
}
|
||||
],
|
||||
[
|
||||
new vscode.NotebookCellOutput([vscode.NotebookCellOutputItem.stdout(['Epoch 1/5\n',
|
||||
'...\n',
|
||||
'Epoch 2/5\n',
|
||||
'...\n',
|
||||
'Epoch 3/5\n',
|
||||
'...\n',
|
||||
'Epoch 4/5\n',
|
||||
'...\n',
|
||||
'Epoch 5/5\n',
|
||||
'...\n'].join(''))], {
|
||||
outputType: 'stream'
|
||||
})
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('Multi-line Stream output (last empty line should not be saved in ipynb)', () => {
|
||||
validateCellOutputTranslation(
|
||||
[
|
||||
{
|
||||
name: 'stderr',
|
||||
output_type: 'stream',
|
||||
text: [
|
||||
'Epoch 1/5\n',
|
||||
'...\n',
|
||||
'Epoch 2/5\n',
|
||||
'...\n',
|
||||
'Epoch 3/5\n',
|
||||
'...\n',
|
||||
'Epoch 4/5\n',
|
||||
'...\n',
|
||||
'Epoch 5/5\n',
|
||||
'...\n'
|
||||
]
|
||||
}
|
||||
],
|
||||
[
|
||||
new vscode.NotebookCellOutput([vscode.NotebookCellOutputItem.stderr(['Epoch 1/5\n',
|
||||
'...\n',
|
||||
'Epoch 2/5\n',
|
||||
'...\n',
|
||||
'Epoch 3/5\n',
|
||||
'...\n',
|
||||
'Epoch 4/5\n',
|
||||
'...\n',
|
||||
'Epoch 5/5\n',
|
||||
'...\n',
|
||||
// This last empty line should not be saved in ipynb.
|
||||
'\n'].join(''))], {
|
||||
outputType: 'stream'
|
||||
})
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('Streamed text with Ansi characters', async () => {
|
||||
validateCellOutputTranslation(
|
||||
|
@ -391,4 +465,131 @@ suite('ipynb serializer', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('Output Order', () => {
|
||||
test('Verify order of outputs', async () => {
|
||||
const dataAndExpectedOrder: { output: nbformat.IDisplayData; expectedMimeTypesOrder: string[] }[] = [
|
||||
{
|
||||
output: {
|
||||
data: {
|
||||
'application/vnd.vegalite.v4+json': 'some json',
|
||||
'text/html': '<a>Hello</a>'
|
||||
},
|
||||
metadata: {},
|
||||
output_type: 'display_data'
|
||||
},
|
||||
expectedMimeTypesOrder: ['application/vnd.vegalite.v4+json', 'text/html']
|
||||
},
|
||||
{
|
||||
output: {
|
||||
data: {
|
||||
'application/vnd.vegalite.v4+json': 'some json',
|
||||
'application/javascript': 'some js',
|
||||
'text/plain': 'some text',
|
||||
'text/html': '<a>Hello</a>'
|
||||
},
|
||||
metadata: {},
|
||||
output_type: 'display_data'
|
||||
},
|
||||
expectedMimeTypesOrder: [
|
||||
'application/vnd.vegalite.v4+json',
|
||||
'text/html',
|
||||
'application/javascript',
|
||||
'text/plain'
|
||||
]
|
||||
},
|
||||
{
|
||||
output: {
|
||||
data: {
|
||||
'application/vnd.vegalite.v4+json': '', // Empty, should give preference to other mimetypes.
|
||||
'application/javascript': 'some js',
|
||||
'text/plain': 'some text',
|
||||
'text/html': '<a>Hello</a>'
|
||||
},
|
||||
metadata: {},
|
||||
output_type: 'display_data'
|
||||
},
|
||||
expectedMimeTypesOrder: [
|
||||
'text/html',
|
||||
'application/javascript',
|
||||
'text/plain',
|
||||
'application/vnd.vegalite.v4+json'
|
||||
]
|
||||
},
|
||||
{
|
||||
output: {
|
||||
data: {
|
||||
'text/plain': 'some text',
|
||||
'text/html': '<a>Hello</a>'
|
||||
},
|
||||
metadata: {},
|
||||
output_type: 'display_data'
|
||||
},
|
||||
expectedMimeTypesOrder: ['text/html', 'text/plain']
|
||||
},
|
||||
{
|
||||
output: {
|
||||
data: {
|
||||
'application/javascript': 'some js',
|
||||
'text/plain': 'some text'
|
||||
},
|
||||
metadata: {},
|
||||
output_type: 'display_data'
|
||||
},
|
||||
expectedMimeTypesOrder: ['application/javascript', 'text/plain']
|
||||
},
|
||||
{
|
||||
output: {
|
||||
data: {
|
||||
'image/svg+xml': 'some svg',
|
||||
'text/plain': 'some text'
|
||||
},
|
||||
metadata: {},
|
||||
output_type: 'display_data'
|
||||
},
|
||||
expectedMimeTypesOrder: ['image/svg+xml', 'text/plain']
|
||||
},
|
||||
{
|
||||
output: {
|
||||
data: {
|
||||
'text/latex': 'some latex',
|
||||
'text/plain': 'some text'
|
||||
},
|
||||
metadata: {},
|
||||
output_type: 'display_data'
|
||||
},
|
||||
expectedMimeTypesOrder: ['text/latex', 'text/plain']
|
||||
},
|
||||
{
|
||||
output: {
|
||||
data: {
|
||||
'application/vnd.jupyter.widget-view+json': 'some widget',
|
||||
'text/plain': 'some text'
|
||||
},
|
||||
metadata: {},
|
||||
output_type: 'display_data'
|
||||
},
|
||||
expectedMimeTypesOrder: ['application/vnd.jupyter.widget-view+json', 'text/plain']
|
||||
},
|
||||
{
|
||||
output: {
|
||||
data: {
|
||||
'text/plain': 'some text',
|
||||
'image/svg+xml': 'some svg',
|
||||
'image/png': 'some png'
|
||||
},
|
||||
metadata: {},
|
||||
output_type: 'display_data'
|
||||
},
|
||||
expectedMimeTypesOrder: ['image/png', 'image/svg+xml', 'text/plain']
|
||||
}
|
||||
];
|
||||
|
||||
dataAndExpectedOrder.forEach(({ output, expectedMimeTypesOrder }) => {
|
||||
const sortedOutputs = jupyterCellOutputToCellOutput(output);
|
||||
const mimeTypes = sortedOutputs.items.map((item) => item.mime).join(',');
|
||||
assert.equal(mimeTypes, expectedMimeTypesOrder.join(','));
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue