提交 cda677da 编写于 作者: J Johannes Rieken

make NotebookConcatTextDocument extends "normal" TextDocument,...

make NotebookConcatTextDocument extends "normal" TextDocument, https://github.com/microsoft/vscode/issues/100186
上级 0980b4d6
......@@ -1454,7 +1454,7 @@ declare module 'vscode' {
metadata: NotebookDocumentMetadata;
}
export interface NotebookConcatTextDocument {
export interface NotebookConcatTextDocument extends TextDocument {
isClosed: boolean;
dispose(): void;
onDidChange: Event<void>;
......
......@@ -12,14 +12,17 @@ import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'
import { DisposableStore } from 'vs/base/common/lifecycle';
import { score } from 'vs/editor/common/modes/languageSelector';
import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { isEqual } from 'vs/base/common/resources';
import { basename } from 'vs/base/common/resources';
import { ResourceMap } from 'vs/base/common/map';
import { ExtHostDocumentLine } from 'vs/workbench/api/common/extHostDocumentData';
export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextDocument {
export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextDocument, vscode.TextDocument {
private _disposables = new DisposableStore();
private _isClosed = false;
private _cells!: ExtHostCell[];
private _cellByUri!: ResourceMap<number>;
private _cellLengths!: PrefixSumComputer;
private _cellLines!: PrefixSumComputer;
private _versionId = 0;
......@@ -27,17 +30,27 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
private readonly _onDidChange = new Emitter<void>();
readonly onDidChange: Event<void> = this._onDidChange.event;
readonly uri: vscode.Uri;
readonly fileName: string;
readonly languageId: string;
readonly isUntitled: boolean = false;
readonly isDirty: boolean = false;
constructor(
extHostNotebooks: ExtHostNotebookController,
extHostDocuments: ExtHostDocuments,
private readonly _notebook: vscode.NotebookDocument,
private readonly _selector: vscode.DocumentSelector | undefined,
) {
this.uri = _notebook.uri.with({ scheme: 'vscode-notebook-concat-doc' });
this.fileName = basename(this.uri);
this.languageId = this._createLanguageId();
this._init();
this._disposables.add(extHostDocuments.onDidChangeDocument(e => {
let cellIdx = this._cells.findIndex(cell => isEqual(cell.uri, e.document.uri));
if (cellIdx >= 0) {
const cellIdx = this._cellByUri.get(e.document.uri);
if (typeof cellIdx === 'number') {
this._cellLengths.changeValue(cellIdx, this._cells[cellIdx].document.getText().length + 1);
this._cellLines.changeValue(cellIdx, this._cells[cellIdx].document.lineCount);
this._versionId += 1;
......@@ -68,10 +81,12 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
private _init() {
this._cells = [];
this._cellByUri = new ResourceMap();
const cellLengths: number[] = [];
const cellLineCounts: number[] = [];
for (let cell of this._notebook.cells) {
if (cell.cellKind === CellKind.Code && (!this._selector || score(this._selector, cell.uri, cell.language, true))) {
this._cellByUri.set(cell.uri, this._cells.length);
this._cells.push(<ExtHostCell>cell);
cellLengths.push(cell.document.getText().length + 1);
cellLineCounts.push(cell.document.lineCount);
......@@ -81,6 +96,67 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
this._cellLines = new PrefixSumComputer(new Uint32Array(cellLineCounts));
}
private _createLanguageId(): string {
const languageIds = new Set<string>();
(function fillInLanguageIds(selector: vscode.DocumentSelector | undefined) {
if (Array.isArray(selector)) {
selector.forEach(fillInLanguageIds);
} else if (typeof selector === 'string') {
languageIds.add(selector);
} else if (selector?.language) {
languageIds.add(selector.language);
}
})(this._selector);
if (languageIds.size === 0) {
return 'unknown';
}
return [...languageIds.values()].sort().join(';');
}
save(): Thenable<boolean> {
// todo@jrieken throw error instead?
return Promise.resolve(false);
}
get eol(): vscode.EndOfLine {
return types.EndOfLine.LF;
}
get lineCount(): number {
let total = 0;
for (let cell of this._cells) {
total += cell.document.lineCount;
}
return total;
}
lineAt(lineOrPosition: number | vscode.Position): vscode.TextLine {
const line = typeof lineOrPosition === 'number' ? lineOrPosition : lineOrPosition.line;
const cellIdx = this._cellLines.getIndexOf(line);
return new ExtHostDocumentLine(
line,
this._cells[cellIdx.index].document.lineAt(cellIdx.remainder).text,
line >= this.lineCount
);
}
getWordRangeAtPosition(position: vscode.Position, regex?: RegExp | undefined): vscode.Range | undefined {
const cellIdx = this._cellLines.getIndexOf(position.line);
return this._cells[cellIdx.index].document.getWordRangeAtPosition(position.with({ line: cellIdx.remainder }), regex);
}
validateRange(range: vscode.Range): vscode.Range {
const start = this.validatePosition(range.start);
const end = this.validatePosition(range.end);
return range.with({ start, end });
}
validatePosition(position: vscode.Position): vscode.Position {
const cellIdx = this._cellLines.getIndexOf(position.line);
return this._cells[cellIdx.index].document.validatePosition(position.with({ line: cellIdx.remainder }));
}
get version(): number {
return this._versionId;
}
......@@ -103,8 +179,8 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
// get start and end locations and create substrings
const start = this.locationAt(range.start);
const end = this.locationAt(range.end);
const startCell = this._cells.find(cell => isEqual(cell.uri, start.uri));
const endCell = this._cells.find(cell => isEqual(cell.uri, end.uri));
const startCell = this._cells[this._cellByUri.get(start.uri) ?? -1];
const endCell = this._cells[this._cellByUri.get(end.uri) ?? -1];
if (!startCell || !endCell) {
return '';
......@@ -131,8 +207,8 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
return this._cells[idx.index].document.positionAt(idx.remainder).translate(lineCount);
}
const idx = this._cells.findIndex(cell => isEqual(cell.uri, locationOrOffset.uri));
if (idx >= 0) {
const idx = this._cellByUri.get(locationOrOffset.uri);
if (typeof idx === 'number') {
let line = this._cellLines.getAccumulatedValue(idx - 1);
return new types.Position(line + locationOrOffset.range.start.line, locationOrOffset.range.start.character);
}
......
......@@ -12,7 +12,7 @@ import { ExtHostNotebookConcatDocument } from 'vs/workbench/api/common/extHostNo
import { ExtHostNotebookDocument, ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
import { URI } from 'vs/base/common/uri';
import { CellKind, CellUri, NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { Position, Location, Range } from 'vs/workbench/api/common/extHostTypes';
import { Position, Location, Range, EndOfLine } from 'vs/workbench/api/common/extHostTypes';
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import * as vscode from 'vscode';
......@@ -28,7 +28,7 @@ suite('NotebookConcatDocument', function () {
let extHostDocumentsAndEditors: ExtHostDocumentsAndEditors;
let extHostDocuments: ExtHostDocuments;
let extHostNotebooks: ExtHostNotebookController;
const notebookUri = URI.parse('test:///notebook.file');
const notebookUri = URI.parse('test:/path/notebook.file');
const disposables = new DisposableStore();
setup(async function () {
......@@ -80,6 +80,19 @@ suite('NotebookConcatDocument', function () {
disposables.add(extHostDocuments);
});
test('basics', async function () {
let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook, undefined);
assert.equal(doc.uri.toString(), 'vscode-notebook-concat-doc:/path/notebook.file');
assert.equal(doc.fileName, 'notebook.file');
assert.equal(doc.isUntitled, false);
assert.equal(doc.isDirty, false);
assert.equal(await doc.save(), false);
assert.equal(doc.isClosed, false);
assert.equal(doc.eol, EndOfLine.LF);
doc.dispose();
assert.equal(doc.isClosed, true);
});
test('empty', function () {
let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook, undefined);
assert.equal(doc.getText(), '');
......@@ -109,6 +122,11 @@ suite('NotebookConcatDocument', function () {
function assertLines(doc: vscode.NotebookConcatTextDocument, ...lines: string[]) {
let actual = doc.getText().split(/\r\n|\n|\r/);
assert.deepStrictEqual(actual, lines);
assert.equal(doc.lineCount, lines.length);
for (let i = 0; i < lines.length; i++) {
assert.equal(doc.lineAt(i).text, lines[i]);
assert.equal(doc.lineAt(i).range.start.line, i);
}
}
test('location, position mapping', function () {
......@@ -302,6 +320,10 @@ suite('NotebookConcatDocument', function () {
const fooLangDoc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook, 'fooLang');
const barLangDoc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook, 'barLang');
assert.equal(mixedDoc.languageId, 'unknown');
assert.equal(fooLangDoc.languageId, 'fooLang');
assert.equal(barLangDoc.languageId, 'barLang');
assertLines(mixedDoc, 'fooLang-document', 'barLang-document');
assertLines(fooLangDoc, 'fooLang-document');
assertLines(barLangDoc, 'barLang-document');
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册