mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-27 12:04:04 +01:00
Fix slow positionAt impl for markdown references
- Use `vscode-languageserver-textdocument` instead of custom impl - Reuse `InMemoryDocument` across tests and working code - Use `SkinnyTextDocument` in more places - Fixes some test errors that seem to be caused by bad `InMemoryDocument` impl
This commit is contained in:
@@ -8,7 +8,7 @@ import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { MdLinkProvider } from '../languageFeatures/documentLinkProvider';
|
||||
import { createNewMarkdownEngine } from './engine';
|
||||
import { InMemoryDocument } from './inMemoryDocument';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
import { joinLines, noopToken } from './util';
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { MdDocumentSymbolProvider } from '../languageFeatures/documentSymbolProvider';
|
||||
import { createNewMarkdownEngine } from './engine';
|
||||
import { InMemoryDocument } from './inMemoryDocument';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
|
||||
|
||||
const testFileName = vscode.Uri.file('test.md');
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as assert from 'assert';
|
||||
import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { createNewMarkdownEngine } from './engine';
|
||||
import { InMemoryDocument } from './inMemoryDocument';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
|
||||
|
||||
const testFileName = vscode.Uri.file('test.md');
|
||||
|
||||
@@ -8,7 +8,7 @@ import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { MdFoldingProvider } from '../languageFeatures/foldingProvider';
|
||||
import { createNewMarkdownEngine } from './engine';
|
||||
import { InMemoryDocument } from './inMemoryDocument';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
|
||||
|
||||
const testFileName = vscode.Uri.file('test.md');
|
||||
@@ -48,10 +48,10 @@ y`);
|
||||
assert.strictEqual(folds.length, 2);
|
||||
const firstFold = folds[0];
|
||||
assert.strictEqual(firstFold.start, 1);
|
||||
assert.strictEqual(firstFold.end, 3);
|
||||
assert.strictEqual(firstFold.end, 2);
|
||||
});
|
||||
|
||||
test('Should collapse multuple newlines to single newline before next header', async () => {
|
||||
test('Should collapse multiple newlines to single newline before next header', async () => {
|
||||
const folds = await getFoldsForDocument(`
|
||||
# a
|
||||
x
|
||||
@@ -63,7 +63,7 @@ y`);
|
||||
assert.strictEqual(folds.length, 2);
|
||||
const firstFold = folds[0];
|
||||
assert.strictEqual(firstFold.start, 1);
|
||||
assert.strictEqual(firstFold.end, 5);
|
||||
assert.strictEqual(firstFold.end, 4);
|
||||
});
|
||||
|
||||
test('Should not collapse if there is no newline before next header', async () => {
|
||||
@@ -132,7 +132,7 @@ b`);
|
||||
assert.strictEqual(folds.length, 1);
|
||||
const firstFold = folds[0];
|
||||
assert.strictEqual(firstFold.start, 0);
|
||||
assert.strictEqual(firstFold.end, 3);
|
||||
assert.strictEqual(firstFold.end, 2);
|
||||
});
|
||||
|
||||
test('Should fold fenced code blocks', async () => {
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as os from 'os';
|
||||
import * as vscode from 'vscode';
|
||||
export class InMemoryDocument implements vscode.TextDocument {
|
||||
private readonly _lines: string[];
|
||||
|
||||
constructor(
|
||||
public readonly uri: vscode.Uri,
|
||||
private readonly _contents: string,
|
||||
public readonly version = 1,
|
||||
) {
|
||||
this._lines = this._contents.split(/\r\n|\n/g);
|
||||
}
|
||||
|
||||
isUntitled: boolean = false;
|
||||
languageId: string = '';
|
||||
isDirty: boolean = false;
|
||||
isClosed: boolean = false;
|
||||
eol: vscode.EndOfLine = os.platform() === 'win32' ? vscode.EndOfLine.CRLF : vscode.EndOfLine.LF;
|
||||
notebook: undefined;
|
||||
|
||||
get fileName(): string {
|
||||
return this.uri.fsPath;
|
||||
}
|
||||
|
||||
get lineCount(): number {
|
||||
return this._lines.length;
|
||||
}
|
||||
|
||||
lineAt(line: any): vscode.TextLine {
|
||||
return {
|
||||
lineNumber: line,
|
||||
text: this._lines[line],
|
||||
range: new vscode.Range(0, 0, 0, 0),
|
||||
firstNonWhitespaceCharacterIndex: 0,
|
||||
rangeIncludingLineBreak: new vscode.Range(0, 0, 0, 0),
|
||||
isEmptyOrWhitespace: false
|
||||
};
|
||||
}
|
||||
offsetAt(_position: vscode.Position): never {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
positionAt(offset: number): vscode.Position {
|
||||
const before = this._contents.slice(0, offset);
|
||||
const newLines = before.match(/\r\n|\n/g);
|
||||
const line = newLines ? newLines.length : 0;
|
||||
// eslint-disable-next-line code-no-look-behind-regex
|
||||
const preCharacters = before.match(/(?<=\r\n|\n|^).*$/g);
|
||||
return new vscode.Position(line, preCharacters ? preCharacters[0].length : 0);
|
||||
}
|
||||
getText(range?: vscode.Range): string {
|
||||
if (!range) {
|
||||
return this._contents;
|
||||
}
|
||||
|
||||
if (range.start.line !== range.end.line) {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
return this._lines[range.start.line].slice(range.start.character, range.end.character);
|
||||
}
|
||||
getWordRangeAtPosition(_position: vscode.Position, _regex?: RegExp | undefined): never {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
validateRange(_range: vscode.Range): never {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
validatePosition(_position: vscode.Position): never {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
save(): never {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
@@ -5,15 +5,15 @@
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as vscode from 'vscode';
|
||||
import { MdWorkspaceContents } from '../workspaceContents';
|
||||
import { MdWorkspaceContents, SkinnyTextDocument } from '../workspaceContents';
|
||||
|
||||
|
||||
export class InMemoryWorkspaceMarkdownDocuments implements MdWorkspaceContents {
|
||||
private readonly _documents = new Map<string, vscode.TextDocument>();
|
||||
private readonly _documents = new Map<string, SkinnyTextDocument>();
|
||||
|
||||
constructor(documents: vscode.TextDocument[]) {
|
||||
constructor(documents: SkinnyTextDocument[]) {
|
||||
for (const doc of documents) {
|
||||
this._documents.set(doc.fileName, doc);
|
||||
this._documents.set(doc.uri.toString(), doc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,29 +21,29 @@ export class InMemoryWorkspaceMarkdownDocuments implements MdWorkspaceContents {
|
||||
return Array.from(this._documents.values());
|
||||
}
|
||||
|
||||
private readonly _onDidChangeMarkdownDocumentEmitter = new vscode.EventEmitter<vscode.TextDocument>();
|
||||
private readonly _onDidChangeMarkdownDocumentEmitter = new vscode.EventEmitter<SkinnyTextDocument>();
|
||||
public onDidChangeMarkdownDocument = this._onDidChangeMarkdownDocumentEmitter.event;
|
||||
|
||||
private readonly _onDidCreateMarkdownDocumentEmitter = new vscode.EventEmitter<vscode.TextDocument>();
|
||||
private readonly _onDidCreateMarkdownDocumentEmitter = new vscode.EventEmitter<SkinnyTextDocument>();
|
||||
public onDidCreateMarkdownDocument = this._onDidCreateMarkdownDocumentEmitter.event;
|
||||
|
||||
private readonly _onDidDeleteMarkdownDocumentEmitter = new vscode.EventEmitter<vscode.Uri>();
|
||||
public onDidDeleteMarkdownDocument = this._onDidDeleteMarkdownDocumentEmitter.event;
|
||||
|
||||
public updateDocument(document: vscode.TextDocument) {
|
||||
this._documents.set(document.fileName, document);
|
||||
public updateDocument(document: SkinnyTextDocument) {
|
||||
this._documents.set(document.uri.toString(), document);
|
||||
this._onDidChangeMarkdownDocumentEmitter.fire(document);
|
||||
}
|
||||
|
||||
public createDocument(document: vscode.TextDocument) {
|
||||
assert.ok(!this._documents.has(document.uri.fsPath));
|
||||
public createDocument(document: SkinnyTextDocument) {
|
||||
assert.ok(!this._documents.has(document.uri.toString()));
|
||||
|
||||
this._documents.set(document.uri.fsPath, document);
|
||||
this._documents.set(document.uri.toString(), document);
|
||||
this._onDidCreateMarkdownDocumentEmitter.fire(document);
|
||||
}
|
||||
|
||||
public deleteDocument(resource: vscode.Uri) {
|
||||
this._documents.delete(resource.fsPath);
|
||||
this._documents.delete(resource.toString());
|
||||
this._onDidDeleteMarkdownDocumentEmitter.fire(resource);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import * as vscode from 'vscode';
|
||||
import { MdLinkProvider } from '../languageFeatures/documentLinkProvider';
|
||||
import { MdPathCompletionProvider } from '../languageFeatures/pathCompletions';
|
||||
import { createNewMarkdownEngine } from './engine';
|
||||
import { InMemoryDocument } from './inMemoryDocument';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
import { CURSOR, getCursorPositions, joinLines, noopToken } from './util';
|
||||
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { MdLinkProvider } from '../languageFeatures/documentLinkProvider';
|
||||
import { MdReferencesProvider } from '../languageFeatures/references';
|
||||
import { MdWorkspaceContents } from '../workspaceContents';
|
||||
import { createNewMarkdownEngine } from './engine';
|
||||
import { InMemoryDocument } from './inMemoryDocument';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
import { InMemoryWorkspaceMarkdownDocuments } from './inMemoryWorkspace';
|
||||
import { joinLines, noopToken, workspaceFile } from './util';
|
||||
|
||||
@@ -22,7 +22,7 @@ function getReferences(doc: InMemoryDocument, pos: vscode.Position, workspaceCon
|
||||
return provider.provideReferences(doc, pos, { includeDeclaration: true }, noopToken);
|
||||
}
|
||||
|
||||
suite.only('markdown header references', () => {
|
||||
suite('markdown header references', () => {
|
||||
test('Should not return references when not on header', async () => {
|
||||
const doc = new InMemoryDocument(workspaceFile('doc.md'), joinLines(
|
||||
`# abc`,
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as assert from 'assert';
|
||||
import * as vscode from 'vscode';
|
||||
import { MdSmartSelect } from '../languageFeatures/smartSelect';
|
||||
import { createNewMarkdownEngine } from './engine';
|
||||
import { InMemoryDocument } from './inMemoryDocument';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
import { CURSOR, getCursorPositions, joinLines } from './util';
|
||||
|
||||
const testFileName = vscode.Uri.file('test.md');
|
||||
@@ -197,34 +197,35 @@ suite('markdown.SmartSelect', () => {
|
||||
test('Smart select fenced code block then list then subheader content then subheader then header content then header', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`# main header 1`,
|
||||
`content 1`,
|
||||
`## sub header 1`,
|
||||
`- item 1`,
|
||||
`- ~~~`,
|
||||
` ${CURSOR}a`,
|
||||
` ~~~`,
|
||||
`- item 3`,
|
||||
`- item 4`,
|
||||
``,
|
||||
`more content`,
|
||||
`# main header 2`));
|
||||
/* 00 */ `# main header 1`,
|
||||
/* 01 */ `content 1`,
|
||||
/* 02 */ `## sub header 1`,
|
||||
/* 03 */ `- item 1`,
|
||||
/* 04 */ `- ~~~`,
|
||||
/* 05 */ ` ${CURSOR}a`,
|
||||
/* 06 */ ` ~~~`,
|
||||
/* 07 */ `- item 3`,
|
||||
/* 08 */ `- item 4`,
|
||||
/* 09 */ ``,
|
||||
/* 10 */ `more content`,
|
||||
/* 11 */ `# main header 2`));
|
||||
|
||||
assertNestedLineNumbersEqual(ranges![0], [4, 6], [3, 9], [3, 10], [2, 10], [1, 10], [0, 10]);
|
||||
assertNestedLineNumbersEqual(ranges![0], [4, 6], [3, 8], [3, 10], [2, 10], [1, 10], [0, 10]);
|
||||
});
|
||||
|
||||
test('Smart select list with one element without selecting child subheader', async () => {
|
||||
const ranges = await getSelectionRangesForDocument(
|
||||
joinLines(
|
||||
`# main header 1`,
|
||||
``,
|
||||
`- list ${CURSOR}`,
|
||||
``,
|
||||
`## sub header`,
|
||||
``,
|
||||
`content 2`,
|
||||
`# main header 2`));
|
||||
assertNestedLineNumbersEqual(ranges![0], [2, 2], [2, 3], [1, 3], [1, 6], [0, 6]);
|
||||
/* 00 */ `# main header 1`,
|
||||
/* 01 */ ``,
|
||||
/* 02 */ `- list ${CURSOR}`,
|
||||
/* 03 */ ``,
|
||||
/* 04 */ `## sub header`,
|
||||
/* 05 */ ``,
|
||||
/* 06 */ `content 2`,
|
||||
/* 07 */ `# main header 2`));
|
||||
|
||||
assertNestedLineNumbersEqual(ranges![0], [2, 2], [1, 3], [1, 6], [0, 6]);
|
||||
});
|
||||
|
||||
test('Smart select content under header then subheaders and their content', async () => {
|
||||
|
||||
@@ -8,7 +8,7 @@ import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { TableOfContents } from '../tableOfContents';
|
||||
import { createNewMarkdownEngine } from './engine';
|
||||
import { InMemoryDocument } from './inMemoryDocument';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
|
||||
|
||||
const testFileName = vscode.Uri.file('test.md');
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as os from 'os';
|
||||
import * as vscode from 'vscode';
|
||||
import { InMemoryDocument } from './inMemoryDocument';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
|
||||
export const joinLines = (...args: string[]) =>
|
||||
args.join(os.platform() === 'win32' ? '\r\n' : '\n');
|
||||
|
||||
@@ -8,8 +8,9 @@ import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { MdDocumentSymbolProvider } from '../languageFeatures/documentSymbolProvider';
|
||||
import { MdWorkspaceSymbolProvider } from '../languageFeatures/workspaceSymbolProvider';
|
||||
import { SkinnyTextDocument } from '../workspaceContents';
|
||||
import { createNewMarkdownEngine } from './engine';
|
||||
import { InMemoryDocument } from './inMemoryDocument';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
import { InMemoryWorkspaceMarkdownDocuments } from './inMemoryWorkspace';
|
||||
|
||||
|
||||
@@ -37,7 +38,7 @@ suite('markdown.WorkspaceSymbolProvider', () => {
|
||||
|
||||
test('Should return all content basic workspace', async () => {
|
||||
const fileNameCount = 10;
|
||||
const files: vscode.TextDocument[] = [];
|
||||
const files: SkinnyTextDocument[] = [];
|
||||
for (let i = 0; i < fileNameCount; ++i) {
|
||||
const testFileName = vscode.Uri.file(`test${i}.md`);
|
||||
files.push(new InMemoryDocument(testFileName, `# common\nabc\n## header${i}`));
|
||||
|
||||
Reference in New Issue
Block a user