Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix activation of linters on unopened files caused by markdown plugin #80506

Merged
merged 11 commits into from
Sep 11, 2019
50 changes: 50 additions & 0 deletions extensions/markdown-language-features/src/docIndex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as vscode from 'vscode';
import { Disposable } from './util/dispose';


export class DocumentIndex extends Disposable {
private _uriMap: Map<string, vscode.TextDocument> = new Map();

constructor() {
super();

for (let doc of vscode.workspace.textDocuments) {
this._registerDoc(doc);
}

this._register(
vscode.workspace.onDidOpenTextDocument((doc) => {
this._registerDoc(doc);
})
);
this._register(
vscode.workspace.onDidCloseTextDocument((doc) => {
this._unregisterDoc(doc.uri);
})
);
}

getByUri(uri: vscode.Uri): vscode.TextDocument | undefined {
return this._uriMap.get(uri.toString());
}

private _registerDoc(doc: vscode.TextDocument) {
const uri = doc.uri.toString();
if (this._uriMap.has(uri)) {
throw new Error(`The document ${uri} is already registered.`);
}
this._uriMap.set(uri, doc);
}

private _unregisterDoc(uri: vscode.Uri) {
if (!this._uriMap.has(uri.toString())) {
throw new Error(`The document ${uri.toString()} is not registered.`);
}
this._uriMap.delete(uri.toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Lazy, lazy } from '../util/lazy';
import MDDocumentSymbolProvider from './documentSymbolProvider';
import { SkinnyTextDocument } from '../tableOfContentsProvider';
import { flatten } from '../util/arrays';
import { DocumentIndex } from '../docIndex';

export interface WorkspaceMarkdownDocumentProvider {
getAllMarkdownDocuments(): Thenable<Iterable<SkinnyTextDocument>>;
Expand All @@ -26,6 +27,7 @@ class VSCodeWorkspaceMarkdownDocumentProvider extends Disposable implements Work
private readonly _onDidDeleteMarkdownDocumentEmitter = this._register(new vscode.EventEmitter<vscode.Uri>());

private _watcher: vscode.FileSystemWatcher | undefined;
private _docIndex: DocumentIndex = this._register(new DocumentIndex());

async getAllMarkdownDocuments() {
const resources = await vscode.workspace.findFiles('**/*.md', '**/node_modules/**');
Expand Down Expand Up @@ -81,8 +83,23 @@ class VSCodeWorkspaceMarkdownDocumentProvider extends Disposable implements Work
}

private async getMarkdownDocument(resource: vscode.Uri): Promise<SkinnyTextDocument | undefined> {
const doc = await vscode.workspace.openTextDocument(resource);
return doc && isMarkdownFile(doc) ? doc : undefined;
let existingDocument = this._docIndex.getByUri(resource);
if (existingDocument) {
return existingDocument;
}

let bytes = await vscode.workspace.fs.readFile(resource);

// We assume that markdown is in UTF-8
let text = Buffer.from(bytes).toString('utf-8');

return Promise.resolve({
uri: resource,
version: 0,
getText: () => {
return text;
}
});
}
}

Expand Down
49 changes: 49 additions & 0 deletions extensions/markdown-language-features/src/lines.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';


export function createTextLine(line: number, offset: number, text: string, lineBreak: string): vscode.TextLine {
let wsRe = /s*/;
let firstNws = 0;
if (wsRe.test(text)) {
firstNws = wsRe.lastIndex;
}
return {
lineNumber: line,
text: text,
range: new vscode.Range(line, offset, line, offset + text.length),
rangeIncludingLineBreak: new vscode.Range(line, offset, line, offset + text.length + lineBreak.length),
firstNonWhitespaceCharacterIndex: firstNws,
isEmptyOrWhitespace: firstNws === text.length
};
}

export function toTextLines(text: string): vscode.TextLine[] {
let current = 0;
let result: vscode.TextLine[] = [];
while (true) {
let nextNewLine = text.indexOf('\r\n', current);
let separator: string;
if (nextNewLine === -1) {
nextNewLine = text.indexOf('\n', current);
if (nextNewLine !== -1) {
separator = '\n';
} else {
separator = '';
}
} else {
separator = '\r\n';
}

if (nextNewLine === -1) {
break;
}
result.push(createTextLine(result.length, current, text.substring(current, nextNewLine), separator));
current = nextNewLine + separator.length;
}
result.push(createTextLine(result.length, current, text.substring(current, text.length), ''));
return result;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import * as vscode from 'vscode';
import { MarkdownEngine } from './markdownEngine';
import { Slug, githubSlugifier } from './slugify';
import { toTextLines } from './lines';

export interface TocEntry {
readonly slug: Slug;
Expand All @@ -18,9 +19,7 @@ export interface TocEntry {
export interface SkinnyTextDocument {
readonly uri: vscode.Uri;
readonly version: number;
readonly lineCount: number;
getText(): string;
lineAt(line: number): vscode.TextLine;
}

export class TableOfContentsProvider {
Expand Down Expand Up @@ -52,11 +51,12 @@ export class TableOfContentsProvider {
const toc: TocEntry[] = [];
const tokens = await this.engine.parse(document);

const lines = toTextLines(document.getText());
const slugCount = new Map<string, number>();

for (const heading of tokens.filter(token => token.type === 'heading_open')) {
const lineNumber = heading.map[0];
const line = document.lineAt(lineNumber);
const line = lines[lineNumber];

let slug = githubSlugifier.fromHeading(line.text);
if (slugCount.has(slug.value)) {
Expand All @@ -72,7 +72,8 @@ export class TableOfContentsProvider {
text: TableOfContentsProvider.getHeaderText(line.text),
level: TableOfContentsProvider.getHeaderLevel(heading.markup),
line: lineNumber,
location: new vscode.Location(document.uri, line.range)
location: new vscode.Location(document.uri,
new vscode.Range(lineNumber, 0, lineNumber, line.text.length))
});
}

Expand All @@ -85,13 +86,13 @@ export class TableOfContentsProvider {
break;
}
}
const endLine = typeof end === 'number' ? end : document.lineCount - 1;
const endLine = end !== undefined ? end : lines.length - 1;
return {
...entry,
location: new vscode.Location(document.uri,
new vscode.Range(
entry.location.range.start,
new vscode.Position(endLine, document.lineAt(endLine).range.end.character)))
new vscode.Position(endLine, lines[endLine].text.length)))
};
});
}
Expand Down
44 changes: 44 additions & 0 deletions extensions/markdown-language-features/src/test/lines.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as assert from 'assert';
import 'mocha';

import { toTextLines, createTextLine } from '../lines';

suite('markdown.toLineData', () => {
test('Empty Document', () => {
let data = toTextLines('');

assert.deepStrictEqual(
data,
[ createTextLine(0, 0, '', '') ]
);
});

test('Unix new lines', () => {
let data = toTextLines('a\nb');

assert.deepStrictEqual(
data,
[
createTextLine(0, 0, 'a', '\n'),
createTextLine(1, 2, 'b', '')
]
);
});

test('Win new lines', () => {
let data = toTextLines('a\r\nb');

assert.deepStrictEqual(
data,
[
createTextLine(0, 0, 'a', '\r\n'),
createTextLine(1, 3, 'b', '')
]
);
});
});