test for ouput compression

This commit is contained in:
Aaron Munger
2023-07-10 11:16:53 -07:00
committed by aamunger
parent 79c495444e
commit 0edc352ebc
3 changed files with 60 additions and 6 deletions
@@ -96,11 +96,15 @@ export class NotebookCellOutputTextModel extends Disposable implements ICellOutp
});
this.outputs.length = 0;
mimeTypes.forEach(mime => {
const compressed = compressOutputItemStreams(mimeOutputs.get(mime)!);
const compressionResult = compressOutputItemStreams(mimeOutputs.get(mime)!);
this.outputs.push({
mime,
data: compressed
data: compressionResult.data
});
if (compressionResult.didCompression) {
// we can't rely on knowing buffer lengths if we've erased previous lines
this.versionedBufferLengths = {};
}
});
}
}
@@ -996,6 +996,7 @@ const textDecoder = new TextDecoder();
* Given a stream of individual stdout outputs, this function will return the compressed lines, escaping some of the common terminal escape codes.
* E.g. some terminal escape codes would result in the previous line getting cleared, such if we had 3 lines and
* last line contained such a code, then the result string would be just the first two lines.
* @returns a single VSBuffer with the concatenated and compressed data, and whether any compression was done.
*/
export function compressOutputItemStreams(outputs: Uint8Array[]) {
const buffers: Uint8Array[] = [];
@@ -1008,13 +1009,17 @@ export function compressOutputItemStreams(outputs: Uint8Array[]) {
startAppending = true;
}
}
compressStreamBuffer(buffers);
return formatStreamText(VSBuffer.concat(buffers.map(buffer => VSBuffer.wrap(buffer))));
const didCompression = compressStreamBuffer(buffers);
const data = formatStreamText(VSBuffer.concat(buffers.map(buffer => VSBuffer.wrap(buffer))));
return { data, didCompression };
}
const MOVE_CURSOR_1_LINE_COMMAND = `${String.fromCharCode(27)}[A`;
export const MOVE_CURSOR_1_LINE_COMMAND = `${String.fromCharCode(27)}[A`;
const MOVE_CURSOR_1_LINE_COMMAND_BYTES = MOVE_CURSOR_1_LINE_COMMAND.split('').map(c => c.charCodeAt(0));
const LINE_FEED = 10;
function compressStreamBuffer(streams: Uint8Array[]) {
let didCompress = false;
streams.forEach((stream, index) => {
if (index === 0 || stream.length < MOVE_CURSOR_1_LINE_COMMAND.length) {
return;
@@ -1029,10 +1034,13 @@ function compressStreamBuffer(streams: Uint8Array[]) {
if (lastIndexOfLineFeed === -1) {
return;
}
didCompress = true;
streams[index - 1] = previousStream.subarray(0, lastIndexOfLineFeed);
streams[index] = stream.subarray(MOVE_CURSOR_1_LINE_COMMAND.length);
}
});
return didCompress;
}
@@ -11,7 +11,7 @@ import { ILanguageService } from 'vs/editor/common/languages/language';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { CellEditType, CellKind, ICellEditOperation, NotebookTextModelChangedEvent, NotebookTextModelWillAddRemoveEvent, SelectionStateType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellEditType, CellKind, ICellEditOperation, MOVE_CURSOR_1_LINE_COMMAND, NotebookTextModelChangedEvent, NotebookTextModelWillAddRemoveEvent, SelectionStateType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { setupInstantiationService, TestCell, valueBytesFromString, withTestNotebook } from 'vs/workbench/contrib/notebook/test/browser/testNotebookEditor';
suite('NotebookTextModel', () => {
@@ -436,6 +436,48 @@ suite('NotebookTextModel', () => {
);
});
test('appending streaming outputs with compression', async function () {
await withTestNotebook(
[
['var a = 1;', 'javascript', CellKind.Code, [], {}],
],
(editor) => {
const textModel = editor.textModel;
textModel.applyEdits([
{
index: 0,
editType: CellEditType.Output,
append: true,
outputs: [{
outputId: 'append1',
outputs: [
{ mime: stdOutMime, data: valueBytesFromString('append 1') },
{ mime: stdOutMime, data: valueBytesFromString('\nappend 1') }]
}]
}], true, undefined, () => undefined, undefined, true);
const [output] = textModel.cells[0].outputs;
assert.strictEqual(output.versionId, 0, 'initial output version should be 0');
textModel.applyEdits([
{
editType: CellEditType.OutputItems,
append: true,
outputId: 'append1',
items: [{
mime: stdOutMime, data: valueBytesFromString(MOVE_CURSOR_1_LINE_COMMAND + '\nappend 2')
}]
}], true, undefined, () => undefined, undefined, true);
assert.strictEqual(output.versionId, 1, 'version should bump per append');
assert.strictEqual(output.outputs[0].data.toString(), 'append 1\nappend 2');
assert.strictEqual(output.appendedSinceVersion(0, stdOutMime), undefined,
'compressing outputs should clear out previous versioned output buffers');
}
);
});
test('appending multiple different mime streaming outputs', async function () {
await withTestNotebook(
[