From 2b5426b4477ecdb602c4bb23fde7bfb2fab254fb Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 20 Apr 2020 12:57:13 +0200 Subject: [PATCH] update prefix-sum when docs change, add offset/position math, tests --- .../common/extHostNotebookConcatDocument.ts | 22 ++++-- .../api/extHostNotebookConcatDocument.test.ts | 79 +++++++++++++++++-- 2 files changed, 91 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/api/common/extHostNotebookConcatDocument.ts b/src/vs/workbench/api/common/extHostNotebookConcatDocument.ts index 86721de3f54..85c59d03e8a 100644 --- a/src/vs/workbench/api/common/extHostNotebookConcatDocument.ts +++ b/src/vs/workbench/api/common/extHostNotebookConcatDocument.ts @@ -34,8 +34,8 @@ export class ExtHostNotebookConcatDocument { this._init(); extHostDocuments.onDidChangeDocument(e => { - const cell = this._notebook.cells.find(candidate => candidate.uri.toString() === e.document.uri.toString()); - if (!cell) { + const cellIdx = this._notebook.cells.findIndex(candidate => candidate.uri.toString() === e.document.uri.toString()); + if (cellIdx < 0) { return; } // todo@jrieken reuse raw event! @@ -52,6 +52,8 @@ export class ExtHostNotebookConcatDocument { }; }) }); + this._cellStarts.changeValue(cellIdx, e.document.getText().length + 1); + this._onDidChange.fire(this); }, undefined, this._disposables); @@ -106,6 +108,7 @@ export class ExtHostNotebookConcatDocument { return this._delegate.getText(); } + locationAt(position: vscode.Position): vscode.Location { const offset = this._delegate.document.offsetAt(position); const index = this._cellStarts.getIndexOf(offset); @@ -119,15 +122,24 @@ export class ExtHostNotebookConcatDocument { return new types.Location(cell.uri, cellPos); } - positionAt(location: vscode.Location): vscode.Position { - const idx = this._notebook.cells.findIndex(candidate => candidate.uri.toString() === location.uri.toString()); + positionAt(offset: number): vscode.Position; + positionAt(location: vscode.Location): vscode.Position; + positionAt(offsetOrLocation: number | vscode.Location): vscode.Position { + if (typeof offsetOrLocation === 'number') { + return this._delegate.document.positionAt(offsetOrLocation); + } + const idx = this._notebook.cells.findIndex(candidate => candidate.uri.toString() === offsetOrLocation.uri.toString()); if (idx < 0) { // do better? // return undefined; return new types.Position(0, 0); } - const docOffset = this._notebook.cells[idx].document.offsetAt(location.range.start); + const docOffset = this._notebook.cells[idx].document.offsetAt(offsetOrLocation.range.start); const cellOffset = this._cellStarts.getAccumulatedValue(idx - 1); return this._delegate.document.positionAt(docOffset + cellOffset); } + + offsetAt(position: vscode.Position): number { + return this._delegate.document.offsetAt(position); + } } diff --git a/src/vs/workbench/test/browser/api/extHostNotebookConcatDocument.test.ts b/src/vs/workbench/test/browser/api/extHostNotebookConcatDocument.test.ts index e3466539767..bdf551e75da 100644 --- a/src/vs/workbench/test/browser/api/extHostNotebookConcatDocument.test.ts +++ b/src/vs/workbench/test/browser/api/extHostNotebookConcatDocument.test.ts @@ -25,6 +25,7 @@ suite('NotebookConcatDocument', function () { let rpcProtocol: TestRPCProtocol; let notebook: ExtHostNotebookDocument; + let extHostDocumentsAndEditors: ExtHostDocumentsAndEditors; let extHostDocuments: ExtHostDocuments; let extHostNotebooks: ExtHostNotebookController; const notebookUri = URI.parse('test:///notebook.file'); @@ -42,7 +43,7 @@ suite('NotebookConcatDocument', function () { async $unregisterNotebookProvider() { } async $createNotebookDocument() { } }); - const extHostDocumentsAndEditors = new ExtHostDocumentsAndEditors(rpcProtocol, new NullLogService()); + extHostDocumentsAndEditors = new ExtHostDocumentsAndEditors(rpcProtocol, new NullLogService()); extHostDocuments = new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors); extHostNotebooks = new ExtHostNotebookController(rpcProtocol, new ExtHostCommands(rpcProtocol, new NullLogService()), extHostDocumentsAndEditors); let reg = extHostNotebooks.registerNotebookProvider(nullExtensionDescription, 'test', new class extends mock() { @@ -67,13 +68,17 @@ suite('NotebookConcatDocument', function () { // assert.equal(doc.positionAt(SOME_FAKE_LOCATION?), undefined); }); - function assertLocation(doc: ExtHostNotebookConcatDocument, pos: Position, expected: Location, identCheck = true) { + function assertLocation(doc: ExtHostNotebookConcatDocument, pos: Position, expected: Location, reverse = true) { const actual = doc.locationAt(pos); assert.equal(actual.uri.toString(), expected.uri.toString()); assert.equal(actual.range.isEqual(expected.range), true); - if (identCheck) { - // reverse + if (reverse) { + // reverse - offset + const offset = doc.offsetAt(pos); + assert.equal(doc.positionAt(offset).isEqual(pos), true); + + // reverse - pos const actualPosition = doc.positionAt(actual); assert.equal(actualPosition.isEqual(pos), true); } @@ -114,7 +119,7 @@ suite('NotebookConcatDocument', function () { }); - test('location, position mapping, changes', function () { + test('location, position mapping, cell changes', function () { let doc = new ExtHostNotebookConcatDocument(notebook, extHostNotebooks, extHostDocuments); @@ -171,6 +176,70 @@ suite('NotebookConcatDocument', function () { assertLocation(doc, new Position(0, 0), new Location(notebook.cells[0].uri, new Position(0, 0))); assertLocation(doc, new Position(2, 2), new Location(notebook.cells[0].uri, new Position(2, 2))); assertLocation(doc, new Position(4, 0), new Location(notebook.cells[0].uri, new Position(2, 12)), false); // clamped + }); + + test('location, position mapping, cell-document changes', function () { + + let doc = new ExtHostNotebookConcatDocument(notebook, extHostNotebooks, extHostDocuments); + + // UPDATE 1 + extHostNotebooks.$acceptModelChanged(notebookUri, { + versionId: notebook.versionId + 1, + changes: [[0, 0, [{ + handle: 1, + uri: CellUri.generate(notebook.uri, 1), + source: ['Hello', 'World', 'Hello World!'], + language: 'test', + cellKind: CellKind.Code, + outputs: [], + }, { + handle: 2, + uri: CellUri.generate(notebook.uri, 2), + source: ['Hallo', 'Welt', 'Hallo Welt!'], + language: 'test', + cellKind: CellKind.Code, + outputs: [], + }]]] + }); + assert.equal(notebook.cells.length, 2); + assert.equal(doc.versionId, 1); + + assert.equal(doc.getText(), ['Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!'].join('\n')); + assertLocation(doc, new Position(0, 0), new Location(notebook.cells[0].uri, new Position(0, 0))); + assertLocation(doc, new Position(2, 2), new Location(notebook.cells[0].uri, new Position(2, 2))); + assertLocation(doc, new Position(2, 12), new Location(notebook.cells[0].uri, new Position(2, 12))); + assertLocation(doc, new Position(4, 0), new Location(notebook.cells[1].uri, new Position(1, 0))); + assertLocation(doc, new Position(4, 3), new Location(notebook.cells[1].uri, new Position(1, 3))); + + // offset math + let cell1End = doc.offsetAt(new Position(2, 12)); + assert.equal(doc.positionAt(cell1End).isEqual(new Position(2, 12)), true); + + extHostDocumentsAndEditors.$acceptDocumentsAndEditorsDelta({ + addedDocuments: [{ + uri: notebook.cells[0].uri, + versionId: 1, + lines: ['Hello', 'World', 'Hello World!'], + EOL: '\n', + modeId: '', + isDirty: false + }] + }); + + extHostDocuments.$acceptModelChanged(notebook.cells[0].uri, { + versionId: 0, + eol: '\n', + changes: [{ + range: { startLineNumber: 3, startColumn: 1, endLineNumber: 3, endColumn: 6 }, + rangeLength: 6, + rangeOffset: 12, + text: 'Hi' + }] + }, false); + assert.equal(doc.getText(), ['Hello', 'World', 'Hi World!', 'Hallo', 'Welt', 'Hallo Welt!'].join('\n')); + assertLocation(doc, new Position(2, 12), new Location(notebook.cells[0].uri, new Position(2, 9)), false); + + assert.equal(doc.positionAt(cell1End).isEqual(new Position(3, 2)), true); }); });